Repository: trafficserver
Updated Branches:
  refs/heads/master be428d6f4 -> 0c358a4b1


TS-2863: Enable FQDN selection for shared sessions.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/0c358a4b
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/0c358a4b
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/0c358a4b

Branch: refs/heads/master
Commit: 0c358a4b166b3dbeb847634cc575e8dec06eff7f
Parents: be428d6
Author: Alan M. Carroll <[email protected]>
Authored: Sat May 31 22:41:27 2014 -0500
Committer: Alan M. Carroll <[email protected]>
Committed: Thu Jul 24 20:22:06 2014 -0500

----------------------------------------------------------------------
 doc/arch/hacking/config-var-impl.en.rst |   2 +-
 doc/arch/hacking/index.en.rst           |   2 +-
 iocore/eventsystem/I_EThread.h          |   4 +-
 iocore/eventsystem/UnixEThread.cc       |   2 +-
 lib/ts/INK_MD5.h                        |  26 ++-
 lib/ts/Map.h                            |   2 +-
 lib/ts/ink_code.cc                      |   4 +-
 lib/ts/ink_code.h                       |   2 +-
 lib/ts/ink_inet.h                       |  15 ++
 proxy/Plugin.h                          |   3 +
 proxy/http/HttpSM.cc                    |   8 +-
 proxy/http/HttpServerSession.h          |  10 +-
 proxy/http/HttpSessionManager.cc        | 290 ++++++++++++---------------
 proxy/http/HttpSessionManager.h         | 100 ++++++---
 14 files changed, 253 insertions(+), 217 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/doc/arch/hacking/config-var-impl.en.rst
----------------------------------------------------------------------
diff --git a/doc/arch/hacking/config-var-impl.en.rst 
b/doc/arch/hacking/config-var-impl.en.rst
index 75a80e1..2f3a584 100644
--- a/doc/arch/hacking/config-var-impl.en.rst
+++ b/doc/arch/hacking/config-var-impl.en.rst
@@ -206,7 +206,7 @@ Handling Updates
 
 The simplest mechanism for handling updates is the 
``REC_EstablishStaticConfigXXX`` family of functions. This mechanism
 will cause the value in the indicated instance to be updated in place when an 
update to :file:`records.config` occurs.
-This is done asynchronously using atomic operations. Use of these variables 
must keep that in mind. Adding ``volatile`` to the declaration is likely to be 
a good idea.
+This is done asynchronously using atomic operations. Use of these variables 
must keep that in mind.
 
 If a variable requires additional handling when updated a callback can be 
registered which is called when the variable
 is updated. This is what the ``REC_EstablishStaticConfigXXX`` calls do 
internally with a callback that simply reads the

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/doc/arch/hacking/index.en.rst
----------------------------------------------------------------------
diff --git a/doc/arch/hacking/index.en.rst b/doc/arch/hacking/index.en.rst
index 84e997a..68fd419 100644
--- a/doc/arch/hacking/index.en.rst
+++ b/doc/arch/hacking/index.en.rst
@@ -25,6 +25,6 @@ This is a documentation stub on how to hack Apache Traffic 
Server. Here we try t
 and run unit or regression tests or how to inspect the state of the core with 
a debugger.
 
 .. toctree::
-   :maxdepth: 1
+   :maxdepth: 2
 
    config-var-impl.en

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/iocore/eventsystem/I_EThread.h
----------------------------------------------------------------------
diff --git a/iocore/eventsystem/I_EThread.h b/iocore/eventsystem/I_EThread.h
index f557471..1aca68d 100644
--- a/iocore/eventsystem/I_EThread.h
+++ b/iocore/eventsystem/I_EThread.h
@@ -44,7 +44,7 @@
 struct DiskHandler;
 struct EventIO;
 
-class SessionBucket;
+class ServerSessionPool;
 class Event;
 class Continuation;
 
@@ -322,7 +322,7 @@ public:
   ThreadType tt;
   Event *oneevent;              // For dedicated event thread
 
-  SessionBucket* l1_hash;
+  ServerSessionPool* server_session_pool;
 };
 
 /**

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/iocore/eventsystem/UnixEThread.cc
----------------------------------------------------------------------
diff --git a/iocore/eventsystem/UnixEThread.cc 
b/iocore/eventsystem/UnixEThread.cc
index bb21748..4c9fed9 100644
--- a/iocore/eventsystem/UnixEThread.cc
+++ b/iocore/eventsystem/UnixEThread.cc
@@ -60,7 +60,7 @@ EThread::EThread(ThreadType att, int anid)
     event_types(0),
     signal_hook(0),
     tt(att),
-    l1_hash(NULL)
+    server_session_pool(NULL)
 {
   ethreads_to_be_signalled = (EThread **)ats_malloc(MAX_EVENT_THREADS * 
sizeof(EThread *));
   memset((char *) ethreads_to_be_signalled, 0, MAX_EVENT_THREADS * 
sizeof(EThread *));

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/lib/ts/INK_MD5.h
----------------------------------------------------------------------
diff --git a/lib/ts/INK_MD5.h b/lib/ts/INK_MD5.h
index b046fa6..37585eb 100644
--- a/lib/ts/INK_MD5.h
+++ b/lib/ts/INK_MD5.h
@@ -1,6 +1,6 @@
 /** @file
 
-  A brief file description
+  MD5 support class.
 
   @section license License
 
@@ -48,7 +48,7 @@ struct INK_MD5
   {
     u64[0] = md5.u64[0];
     u64[1] = md5.u64[1];
-    return md5;
+    return *this;
   }
   uint32_t word(int i)
   {
@@ -58,18 +58,18 @@ struct INK_MD5
   {
     return u8[i];
   }
-  INK_MD5 & loadFromBuffer(char *md5_buf) {
+  INK_MD5 & loadFromBuffer(char const* md5_buf) {
     memcpy((void *) u8, (void *) md5_buf, 16);
     return (*this);
   }
-  INK_MD5 & storeToBuffer(char *md5_buf) {
+  INK_MD5 & storeToBuffer(char const* md5_buf) {
     memcpy((void *) md5_buf, (void *) u8, 16);
     return (*this);
   }
-  INK_MD5 & operator =(char *md5) {
+  INK_MD5 & operator =(char const* md5) {
     return (loadFromBuffer(md5));
   }
-  INK_MD5 & operator =(unsigned char *md5) {
+  INK_MD5 & operator =(unsigned char const* md5) {
     return (loadFromBuffer((char *) md5));
   }
 
@@ -77,13 +77,13 @@ struct INK_MD5
   {
     return (char *) memcpy((void *) md5_str, (void *) u8, 16);
   }
-  void encodeBuffer(unsigned char *buffer, int len)
+  void encodeBuffer(unsigned char const* buffer, int len)
   {
     ink_code_md5(buffer, len, u8);
   }
   void encodeBuffer(const char *buffer, int len)
   {
-    encodeBuffer((unsigned char *) buffer, len);
+    encodeBuffer(reinterpret_cast<unsigned char const*>(buffer), len);
   }
   char *str()
   {
@@ -132,10 +132,15 @@ struct INK_MD5
   {
     return u64[i];
   }
-  bool operator==(INK_MD5 const& md5)
+  bool operator==(INK_MD5 const& md5) const
   {
     return u64[0] == md5.u64[0] && u64[1] == md5.u64[1];
   }
+  bool operator != (INK_MD5 const& that) const
+  {
+    return !(*this == that);
+  }
+
   INK_MD5() {
     u64[0] = 0;
     u64[1] = 0;
@@ -144,6 +149,9 @@ struct INK_MD5
     u64[0] = a1;
     u64[1] = a2;
   }
+
+  /// Static default constructed instance.
+  static INK_MD5 const ZERO;
 };
 
 #endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/lib/ts/Map.h
----------------------------------------------------------------------
diff --git a/lib/ts/Map.h b/lib/ts/Map.h
index 27ea183..11d27a0 100644
--- a/lib/ts/Map.h
+++ b/lib/ts/Map.h
@@ -1385,7 +1385,7 @@ template < typename H > void
 TSHashTable<H>::clear() {
   Bucket null_bucket;
   // Remove the values but not the actual buckets.
-  for ( int i = 0 ; i < m_array.n ; ++i ) {
+  for ( size_t i = 0 ; i < m_array.n ; ++i ) {
     m_array[i] = null_bucket;
   }
   // Clear container data.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/lib/ts/ink_code.cc
----------------------------------------------------------------------
diff --git a/lib/ts/ink_code.cc b/lib/ts/ink_code.cc
index 8cc80eb..f3a403f 100644
--- a/lib/ts/ink_code.cc
+++ b/lib/ts/ink_code.cc
@@ -24,8 +24,10 @@
 #include <string.h>
 #include <stdio.h>
 #include "ink_code.h"
+#include "INK_MD5.h"
 #include "ink_assert.h"
 
+INK_MD5 const INK_MD5::ZERO; // default constructed is correct.
 
 /**
   @brief Wrapper around MD5_Init
@@ -57,7 +59,7 @@ ink_code_incr_md5_final(char *sixteen_byte_hash_pointer, 
INK_DIGEST_CTX * contex
   @return always returns 0, maybe some error checking should be done
 */
 int
-ink_code_md5(unsigned char *input, int input_length, unsigned char 
*sixteen_byte_hash_pointer)
+ink_code_md5(unsigned char const* input, int input_length, unsigned char 
*sixteen_byte_hash_pointer)
 {
   MD5_CTX context;
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/lib/ts/ink_code.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_code.h b/lib/ts/ink_code.h
index 8e9eb38..70bc830 100644
--- a/lib/ts/ink_code.h
+++ b/lib/ts/ink_code.h
@@ -34,7 +34,7 @@ typedef MD5_CTX INK_DIGEST_CTX;
   Wrappers around the MD5 functions, all of this should be depericated and 
just use the functions directly
 */
 
-inkcoreapi int ink_code_md5(unsigned char *input, int input_length, unsigned 
char *sixteen_byte_hash_pointer);
+inkcoreapi int ink_code_md5(unsigned char const* input, int input_length, 
unsigned char *sixteen_byte_hash_pointer);
 inkcoreapi char *ink_code_md5_stringify(char *dest33, const size_t destSize, 
const char *md5);
 inkcoreapi char *ink_code_md5_stringify_fast(char *dest33, const char *md5);
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/lib/ts/ink_inet.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_inet.h b/lib/ts/ink_inet.h
index 30fc036..fcaca0d 100644
--- a/lib/ts/ink_inet.h
+++ b/lib/ts/ink_inet.h
@@ -105,6 +105,9 @@ union IpEndpoint {
   in_port_t& port();
   /// Port in network order.
   in_port_t port() const;
+
+  operator sockaddr* () { return &sa; }
+  operator sockaddr const* () const { return &sa; }
 };
 
 struct ink_gethostbyname_r_data
@@ -762,6 +765,18 @@ inline bool operator != (IpEndpoint const& lhs, IpEndpoint 
const& rhs) {
   return 0 != ats_ip_addr_cmp(&lhs.sa, &rhs.sa);
 }
 
+/// Compare address and port for equality.
+inline bool ats_ip_addr_port_eq(sockaddr const* lhs, sockaddr const* rhs) {
+  bool zret = false;
+  if (lhs->sa_family == rhs->sa_family && ats_ip_port_cast(lhs) == 
ats_ip_port_cast(rhs)) {
+    if (AF_INET == lhs->sa_family)
+      zret = ats_ip4_cast(lhs)->sin_addr.s_addr == 
ats_ip4_cast(rhs)->sin_addr.s_addr;
+    else if (AF_INET6 == lhs->sa_family)
+      zret = 0 == memcmp(&ats_ip6_cast(lhs)->sin6_addr, 
&ats_ip6_cast(rhs)->sin6_addr, sizeof(in6_addr));
+  }
+  return zret;
+}
+
 //@}
 
 /// Get IP TCP/UDP port.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/proxy/Plugin.h
----------------------------------------------------------------------
diff --git a/proxy/Plugin.h b/proxy/Plugin.h
index 8f70f1a..4a23557 100644
--- a/proxy/Plugin.h
+++ b/proxy/Plugin.h
@@ -75,6 +75,9 @@ void plugin_init(void);
 class PluginIdentity
 {
  public:
+  /// Make sure destructor is virtual.
+  virtual ~PluginIdentity() {}
+
   /** Get the plugin tag.
       The returned string must have a lifetime at least as long as the plugin.
       @return A string identifying the plugin or @c NULL.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/proxy/http/HttpSM.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index 1fdfd26..5d7239c 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -4527,11 +4527,10 @@ HttpSM::do_http_server_open(bool raw)
 
     if (existing_ss) {
       // [amc] Not sure if this is the best option, but we don't get here 
unless session sharing is disabled
-      // so there's point in further checking on the match or pool values. But 
why check anything? The
+      // so there's no point in further checking on the match or pool values. 
But why check anything? The
       // client has already exchanged a request with this specific origin 
server and has sent another one
       // shouldn't we just automatically keep the association?
-      if (ats_ip_addr_eq(&existing_ss->server_ip.sa, 
&t_state.current.server->addr.sa) &&
-          ats_ip_port_cast(&existing_ss->server_ip) == 
ats_ip_port_cast(&t_state.current.server->addr)) {
+      if (ats_ip_addr_port_eq(&existing_ss->server_ip.sa, 
&t_state.current.server->addr.sa)) {
         ua_session->attach_server_session(NULL);
         existing_ss->state = HSS_ACTIVE;
         this->attach_server_session(existing_ss);
@@ -4911,7 +4910,8 @@ HttpSM::release_server_session(bool serve_from_cache)
     return;
   }
 
-  if (t_state.current.server->keep_alive == HTTP_KEEPALIVE &&
+  if (TS_SERVER_SESSION_SHARING_MATCH_NONE != 
t_state.txn_conf->server_session_sharing_match &&
+      t_state.current.server->keep_alive == HTTP_KEEPALIVE &&
       t_state.hdr_info.server_response.valid() &&
       (t_state.hdr_info.server_response.status_get() == 
HTTP_STATUS_NOT_MODIFIED ||
        (t_state.hdr_info.server_request.method_get_wksidx() == HTTP_WKSIDX_HEAD

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/proxy/http/HttpServerSession.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpServerSession.h b/proxy/http/HttpServerSession.h
index c4fd75c..a788a35 100644
--- a/proxy/http/HttpServerSession.h
+++ b/proxy/http/HttpServerSession.h
@@ -71,7 +71,7 @@ public:
   HttpServerSession()
     : VConnection(NULL),
       hostname_hash(),
-      host_hash_computed(false), con_id(0), transact_count(0),
+      con_id(0), transact_count(0),
       state(HSS_INIT), to_parent_proxy(false), server_trans_stat(0),
       private_session(false),
       sharing_match(TS_SERVER_SESSION_SHARING_MATCH_BOTH),
@@ -119,7 +119,6 @@ public:
   // Keys for matching hostnames
   IpEndpoint server_ip;
   INK_MD5 hostname_hash;
-  bool host_hash_computed;
 
   int64_t con_id;
   int transact_count;
@@ -145,8 +144,8 @@ public:
   TSServerSessionSharingPoolType sharing_pool;
   //  int share_session;
 
-  LINK(HttpServerSession, lru_link);
-  LINK(HttpServerSession, hash_link);
+  LINK(HttpServerSession, ip_hash_link);
+  LINK(HttpServerSession, host_hash_link);
 
   // Keep track of connection limiting and a pointer to the
   // singleton that keeps track of the connection counts.
@@ -176,9 +175,8 @@ extern ClassAllocator<HttpServerSession> 
httpServerSessionAllocator;
 inline void
 HttpServerSession::attach_hostname(const char *hostname)
 {
-  if (!host_hash_computed) {
+  if (INK_MD5::ZERO == hostname_hash) {
     ink_code_md5((unsigned char *) hostname, strlen(hostname), (unsigned char 
*) &hostname_hash);
-    host_hash_computed = true;
   }
 }
 #endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/proxy/http/HttpSessionManager.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSessionManager.cc b/proxy/http/HttpSessionManager.cc
index 8f68f79..e42dd2c 100644
--- a/proxy/http/HttpSessionManager.cc
+++ b/proxy/http/HttpSessionManager.cc
@@ -36,35 +36,103 @@
 #include "HttpSM.h"
 #include "HttpDebugNames.h"
 
-#define FIRST_LEVEL_HASH(x)   ats_ip_hash(x) % HSM_LEVEL1_BUCKETS
-#define SECOND_LEVEL_HASH(x)  ats_ip_hash(x) % HSM_LEVEL2_BUCKETS
-
 // Initialize a thread to handle HTTP session management
 void
 initialize_thread_for_http_sessions(EThread *thread, int /* thread_index 
ATS_UNUSED */)
 {
-  thread->l1_hash = new SessionBucket[HSM_LEVEL1_BUCKETS];
-  for (int i = 0; i < HSM_LEVEL1_BUCKETS; ++i)
-    thread->l1_hash[i].mutex = new_ProxyMutex();
-  //thread->l1_hash[i].mutex = thread->mutex;
+  thread->server_session_pool = new ServerSessionPool;
 }
 
-
 HttpSessionManager httpSessionManager;
 
-SessionBucket::SessionBucket()
-  : Continuation(NULL)
+ServerSessionPool::ServerSessionPool()
+  : Continuation(new_ProxyMutex()), m_ip_pool(1023), m_host_pool(1023)
 {
-  SET_HANDLER(&SessionBucket::session_handler);
+  SET_HANDLER(&ServerSessionPool::eventHandler);
+  m_ip_pool.setExpansionPolicy(IPHashTable::MANUAL);
+  m_host_pool.setExpansionPolicy(HostHashTable::MANUAL);
+}
+
+void
+ServerSessionPool::purge()
+{ 
+  for ( IPHashTable::iterator last = m_ip_pool.end(), spot = m_ip_pool.begin() 
; spot != last ; ++spot ) {
+    spot->do_io_close();
+  }
+  m_ip_pool.clear();
+  m_host_pool.clear();
+}
+
+bool
+ServerSessionPool::match(HttpServerSession* ss, sockaddr const* addr, INK_MD5 
const& hostname_hash, TSServerSessionSharingMatchType match_style)
+{
+  return TS_SERVER_SESSION_SHARING_MATCH_NONE != match_style && // if no 
matching allowed, fail immediately.
+    // The hostname matches if we're not checking it or it (and the port!) is 
a match.
+    (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)) &&
+    // The IP address matches if we're not checking it or it is a match.
+    (TS_SERVER_SESSION_SHARING_MATCH_HOST == match_style || 
ats_ip_addr_port_eq(ss->server_ip, addr))
+    ;
+}
+
+HttpServerSession*
+ServerSessionPool::acquireSession(sockaddr const* addr, INK_MD5 const& 
hostname_hash, TSServerSessionSharingMatchType match_style)
+{
+  HttpServerSession* zret = NULL;
+
+  if (TS_SERVER_SESSION_SHARING_MATCH_HOST == match_style) {
+    // This is broken out because only in this case do we check the host hash 
first.
+    HostHashTable::Location loc = m_host_pool.find(hostname_hash);
+    if (loc) {
+      zret = loc;
+      m_host_pool.remove(loc);
+      m_ip_pool.remove(m_ip_pool.find(zret));
+    }
+  } else if (TS_SERVER_SESSION_SHARING_MATCH_NONE != match_style) { // 
matching is not disabled.
+    IPHashTable::Location loc = m_ip_pool.find(addr);
+    // If we're matching on the IP address we're done, this one is good enough.
+    // Otherwise we need to scan further matches to match the host name as 
well.
+    // Note we don't have to check the port because it's checked as part of 
the IP address key.
+    if (TS_SERVER_SESSION_SHARING_MATCH_IP != match_style) {
+      while (loc && loc->hostname_hash != hostname_hash)
+        ++loc;
+    }
+    if (loc) {
+      zret = loc;
+      m_ip_pool.remove(loc);
+      m_host_pool.remove(m_host_pool.find(zret));
+    }
+  }
+  return zret;
+}
+
+void
+ServerSessionPool::releaseSession(HttpServerSession* ss)
+{
+  ss->state = HSS_KA_SHARED;
+  // Now we need to issue a read on the connection to detect
+  //  if it closes on us.  We will get called back in the
+  //  continuation for this bucket, ensuring we have the lock
+  //  to remove the connection from our lists
+  ss->do_io_read(this, INT64_MAX, ss->read_buffer);
+
+  // Transfer control of the write side as well
+  ss->do_io_write(this, 0, NULL);
+
+  // we probably don't need the active timeout set, but will leave it for now
+  
ss->get_netvc()->set_inactivity_timeout(ss->get_netvc()->get_inactivity_timeout());
+  ss->get_netvc()->set_active_timeout(ss->get_netvc()->get_active_timeout());
+  // put it in the pools.
+  m_ip_pool.insert(ss);
+  m_host_pool.insert(ss);
+
+  Debug("http_ss", "[%" PRId64 "] [release session] " "session placed into 
shared pool", ss->con_id);
 }
 
-// int SessionBucket::session_handler(int event, void* data)
-//
 //   Called from the NetProcessor to left us know that a
 //    connection has closed down
 //
 int
-SessionBucket::session_handler(int event, void *data)
+ServerSessionPool::eventHandler(int event, void *data)
 {
   NetVConnection *net_vc = NULL;
   HttpServerSession *s = NULL;
@@ -78,7 +146,7 @@ SessionBucket::session_handler(int event, void *data)
   case VC_EVENT_ERROR:
   case VC_EVENT_INACTIVITY_TIMEOUT:
   case VC_EVENT_ACTIVE_TIMEOUT:
-    net_vc = (NetVConnection *) ((VIO *) data)->vc_server;
+    net_vc = static_cast<NetVConnection *>((static_cast<VIO 
*>(data))->vc_server);
     break;
 
   default:
@@ -86,16 +154,12 @@ SessionBucket::session_handler(int event, void *data)
     return 0;
   }
 
-  // Search the 2nd level bucket for appropriate netvc
-  int l2_index = SECOND_LEVEL_HASH(net_vc->get_remote_addr());
+  sockaddr const* addr = net_vc->get_remote_addr();
   HttpConfigParams *http_config_params = HttpConfig::acquire();
   bool found = false;
 
-  ink_assert(l2_index < HSM_LEVEL2_BUCKETS);
-  s = l2_hash[l2_index].head;
-
-  while (s != NULL) {
-    if (s->get_netvc() == net_vc) {
+  for ( ServerSessionPool::IPHashTable::Location lh = m_ip_pool.find(addr) ; 
lh.isValid() ; ++lh ) {
+    if ((s = lh)->get_netvc() == net_vc) {
       // if there was a timeout of some kind on a keep alive connection, and
       // keeping the connection alive will not keep us above the # of max 
connections
       // to the origin and we are below the min number of keep alive 
connections to this
@@ -118,27 +182,26 @@ SessionBucket::session_handler(int event, void *data)
 
       // We've found our server session. Remove it from
       //   our lists and close it down
-      Debug("http_ss", "[%" PRId64 "] [session_bucket] session received io 
notice [%s]",
-            s->con_id, HttpDebugNames::get_event_name(event));
+      Debug("http_ss", "[%" PRId64 "] [session_pool] session %p received io 
notice [%s]",
+            s->con_id, s, HttpDebugNames::get_event_name(event));
       ink_assert(s->state == HSS_KA_SHARED);
-      lru_list.remove(s);
-      l2_hash[l2_index].remove(s);
+      // Out of the pool! Now!
+      m_ip_pool.remove(lh);
+      m_host_pool.remove(m_host_pool.find(s));
+      // Drop connection on this end.
       s->do_io_close();
       found = true;
       break;
-    } else {
-      s = s->hash_link.next;
     }
   }
 
   HttpConfig::release(http_config_params);
-  if (found)
-    return 0;
-
-  // We failed to find our session.  This can only be the result
-  //  of a programming flaw
-  Warning("Connection leak from http keep-alive system");
-  ink_assert(0);
+  if (!found) {
+    // We failed to find our session.  This can only be the result
+    //  of a programming flaw
+    Warning("Connection leak from http keep-alive system");
+    ink_assert(0);
+  }
   return 0;
 }
 
@@ -146,81 +209,20 @@ SessionBucket::session_handler(int event, void *data)
 void
 HttpSessionManager::init()
 {
-  // Initialize our internal (global) hash table
-  for (int i = 0; i < HSM_LEVEL1_BUCKETS; i++) {
-    g_l1_hash[i].mutex = new_ProxyMutex();
-  }
+  m_g_pool = new ServerSessionPool;
 }
 
 // TODO: Should this really purge all keep-alive sessions?
+// Does this make any sense, since we always do the global pool and not the 
per thread?
 void
 HttpSessionManager::purge_keepalives()
 {
   EThread *ethread = this_ethread();
 
-  for (int i = 0; i < HSM_LEVEL1_BUCKETS; i++) {
-    SessionBucket *b = &g_l1_hash[i];
-    MUTEX_TRY_LOCK(lock, b->mutex, ethread);
-    if (lock) {
-      while (b->lru_list.head) {
-        HttpServerSession *sess = b->lru_list.head;
-        b->lru_list.remove(sess);
-        int l2_index = SECOND_LEVEL_HASH(&sess->server_ip.sa);
-        b->l2_hash[l2_index].remove(sess);
-        sess->do_io_close();
-      }
-    } else {
-      // Fix me, should retry
-    }
-  }
-}
-
-bool
-HttpSessionManager::match(HttpServerSession* s, sockaddr const* addr, INK_MD5 
const& hostname_hash, HttpSM* sm)
-{
-  return
-    (TS_SERVER_SESSION_SHARING_MATCH_HOST == 
sm->t_state.txn_conf->server_session_sharing_match || 
-          (ats_ip_addr_eq(&s->server_ip.sa, addr) && 
ats_ip_port_cast(&s->server_ip.sa) == ats_ip_port_cast(addr)))
-    && (TS_SERVER_SESSION_SHARING_MATCH_IP == 
sm->t_state.txn_conf->server_session_sharing_match ||
-        s->hostname_hash == hostname_hash)
-    ;
-}
-
-bool
-HttpSessionManager::match(HttpServerSession* s, sockaddr const* addr, char 
const* hostname, HttpSM* sm)
-{
-  INK_MD5 hostname_hash;
-  ink_code_md5((unsigned char *) hostname, strlen(hostname), 
reinterpret_cast<unsigned char *>(&hostname_hash));
-  return match(s, addr, hostname_hash, sm);
-}
-
-HSMresult_t
-_acquire_session(SessionBucket *bucket, sockaddr const* ip, INK_MD5 
&hostname_hash, HttpSM *sm)
-{
-  HttpServerSession *b;
-  HttpServerSession *to_return = NULL;
-  int l2_index = SECOND_LEVEL_HASH(ip);
-
-  ink_assert(l2_index < HSM_LEVEL2_BUCKETS);
-
-  // Check to see if an appropriate connection is in
-  //  the 2nd level bucket
-  b = bucket->l2_hash[l2_index].head;
-  while (b != NULL) {
-    if (HttpSessionManager::match(b, ip, hostname_hash, sm)) {
-      bucket->lru_list.remove(b);
-      bucket->l2_hash[l2_index].remove(b);
-      b->state = HSS_ACTIVE;
-      to_return = b;
-      Debug("http_ss", "[%" PRId64 "] [acquire session] " "return session from 
shared pool", to_return->con_id);
-      sm->attach_server_session(to_return);
-      return HSM_DONE;
-    }
-
-    b = b->hash_link.next;
-  }
-
-  return HSM_NOT_FOUND;
+  MUTEX_TRY_LOCK(lock, m_g_pool->mutex, ethread);
+  if (lock) {
+    m_g_pool->purge();
+  } // should we do something clever if we don't get the lock?
 }
 
 HSMresult_t
@@ -228,17 +230,7 @@ HttpSessionManager::acquire_session(Continuation * /* cont 
ATS_UNUSED */, sockad
                                     const char *hostname, HttpClientSession 
*ua_session, HttpSM *sm)
 {
   HttpServerSession *to_return = NULL;
-
-  //  We compute the hash for matching the hostname as the last
-  //  check for a match between the session the HttpSM is looking
-  //  for and the sessions we have. We have to use the hostname
-  //  as part of the match because some stupid servers can't
-  //  handle getting request for different virtual hosts over
-  //  the same keep-alive session (INKqa05429).
-  // 
-  //  Also, note the ip is required as well to maintain client
-  //  to server affinity so that we don't break certain types
-  //  of authentication.
+  TSServerSessionSharingMatchType match_style = 
static_cast<TSServerSessionSharingMatchType>(sm->t_state.txn_conf->server_session_sharing_match);
   INK_MD5 hostname_hash;
 
   ink_code_md5((unsigned char *) hostname, strlen(hostname), (unsigned char *) 
&hostname_hash);
@@ -249,7 +241,7 @@ HttpSessionManager::acquire_session(Continuation * /* cont 
ATS_UNUSED */, sockad
   if (to_return != NULL) {
     ua_session->attach_server_session(NULL);
 
-    if (match(to_return, ip, hostname_hash, sm)) {
+    if (ServerSessionPool::match(to_return, ip, hostname_hash, match_style)) {
       Debug("http_ss", "[%" PRId64 "] [acquire session] returning attached 
session ", to_return->con_id);
       to_return->state = HSS_ACTIVE;
       sm->attach_server_session(to_return);
@@ -262,74 +254,46 @@ HttpSessionManager::acquire_session(Continuation * /* 
cont ATS_UNUSED */, sockad
     to_return = NULL;
   }
 
-  // Now check to see if we have a connection is our
-  //  shared connection pool
-  int l1_index = FIRST_LEVEL_HASH(ip);
+  // Now check to see if we have a connection in our shared connection pool
   EThread *ethread = this_ethread();
 
-  ink_assert(l1_index < HSM_LEVEL1_BUCKETS);
-
   if (TS_SERVER_SESSION_SHARING_POOL_THREAD == 
sm->t_state.txn_conf->server_session_sharing_pool) {
-    ink_assert(ethread->l1_hash);
-    return _acquire_session(ethread->l1_hash + l1_index, ip, hostname_hash, 
sm);
+    to_return = ethread->server_session_pool->acquireSession(ip, 
hostname_hash, match_style);
   } else {
-    SessionBucket *bucket = g_l1_hash + l1_index;
-
-    MUTEX_TRY_LOCK(lock, bucket->mutex, ethread);
+    MUTEX_TRY_LOCK(lock, m_g_pool->mutex, ethread);
     if (lock) {
-      return _acquire_session(bucket, ip, hostname_hash, sm);
+      to_return = m_g_pool->acquireSession(ip, hostname_hash, match_style);
+      Debug("http_ss", "[acquire session] pool search %s", to_return ? 
"successful" : "failed");
     } else {
       Debug("http_ss", "[acquire session] could not acquire session due to 
lock contention");
+      return HSM_RETRY;
     }
   }
 
-  return HSM_RETRY;
+  if (to_return) {
+    Debug("http_ss", "[%" PRId64 "] [acquire session] " "return session from 
shared pool", to_return->con_id);
+    to_return->state = HSS_ACTIVE;
+    sm->attach_server_session(to_return);
+    return HSM_DONE;
+  }
+  return HSM_NOT_FOUND;
 }
 
 HSMresult_t
 HttpSessionManager::release_session(HttpServerSession *to_release)
 {
   EThread *ethread = this_ethread();
-  int l1_index = FIRST_LEVEL_HASH(&to_release->server_ip.sa);
-  SessionBucket *bucket;
-
-  ink_assert(l1_index < HSM_LEVEL1_BUCKETS);
-
-  if (TS_SERVER_SESSION_SHARING_POOL_THREAD == to_release->sharing_pool) {
-    bucket = ethread->l1_hash + l1_index;
-  } else {
-    bucket = g_l1_hash + l1_index;
-  }
-
-  MUTEX_TRY_LOCK(lock, bucket->mutex, ethread);
+  ServerSessionPool* pool = TS_SERVER_SESSION_SHARING_POOL_THREAD == 
to_release->sharing_pool ? ethread->server_session_pool : m_g_pool;
+  bool released_p = true;
+  
+  // The per thread lock looks like it should not be needed but if it's not 
locked the close checking I/O op will crash.
+  MUTEX_TRY_LOCK(lock, pool->mutex, ethread);
   if (lock) {
-    int l2_index = SECOND_LEVEL_HASH(&to_release->server_ip.sa);
-
-    ink_assert(l2_index < HSM_LEVEL2_BUCKETS);
-
-    // First insert the session on to our lists
-    bucket->lru_list.enqueue(to_release);
-    bucket->l2_hash[l2_index].push(to_release);
-    to_release->state = HSS_KA_SHARED;
-
-    // Now we need to issue a read on the connection to detect
-    //  if it closes on us.  We will get called back in the
-    //  continuation for this bucket, ensuring we have the lock
-    //  to remove the connection from our lists
-    to_release->do_io_read(bucket, INT64_MAX, to_release->read_buffer);
-
-    // Transfer control of the write side as well
-    to_release->do_io_write(bucket, 0, NULL);
-
-    // we probably don't need the active timeout set, but will leave it for now
-    
to_release->get_netvc()->set_inactivity_timeout(to_release->get_netvc()->get_inactivity_timeout());
-    
to_release->get_netvc()->set_active_timeout(to_release->get_netvc()->get_active_timeout());
-    Debug("http_ss", "[%" PRId64 "] [release session] " "session placed into 
shared pool", to_release->con_id);
-
-    return HSM_DONE;
+    pool->releaseSession(to_release);
   } else {
     Debug("http_ss", "[%" PRId64 "] [release session] could not release 
session due to lock contention", to_release->con_id);
+    released_p = false;
   }
 
-  return HSM_RETRY;
+  return released_p ? HSM_DONE : HSM_RETRY;
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0c358a4b/proxy/http/HttpSessionManager.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSessionManager.h b/proxy/http/HttpSessionManager.h
index f6086eb..442a5c1 100644
--- a/proxy/http/HttpSessionManager.h
+++ b/proxy/http/HttpSessionManager.h
@@ -36,6 +36,7 @@
 
 #include "P_EventSystem.h"
 #include "HttpServerSession.h"
+#include <ts/Map.h>
 
 class HttpClientSession;
 class HttpSM;
@@ -43,16 +44,77 @@ class HttpSM;
 void
 initialize_thread_for_http_sessions(EThread *thread, int thread_index);
 
-#define  HSM_LEVEL1_BUCKETS   127
-#define  HSM_LEVEL2_BUCKETS   63
+/** A pool of server sessions.
 
-class SessionBucket: public Continuation
+    This is a continuation so that it can get callbacks from the server 
sessions.
+    This is used to track remote closes on the sessions so they can be cleaned 
up.
+
+    @internal Cleanup is the real reason we will always need an IP address 
mapping for the
+    sessions. The I/O callback will have only the NetVC and thence the remote 
IP address for the
+    closed session and we need to be able find it based on that.
+*/
+class ServerSessionPool: public Continuation
 {
 public:
-  SessionBucket();
-  int session_handler(int event, void *data);
-  Que(HttpServerSession, lru_link) lru_list;
-  DList(HttpServerSession, hash_link) l2_hash[HSM_LEVEL2_BUCKETS];
+  /// Default constructor.
+  /// Constructs an empty pool.
+  ServerSessionPool();
+  /// Handle events from server sessions.
+  int eventHandler(int event, void *data);
+ protected:
+  /// Interface class for IP map.
+  struct IPHashing
+  {
+    typedef uint32_t ID;
+    typedef sockaddr const* Key;
+    typedef HttpServerSession Value;
+    typedef DList(HttpServerSession, ip_hash_link) ListHead;
+
+    static ID hash(Key key) { return ats_ip_hash(key); }
+    static Key key(Value const* value) { return &value->server_ip.sa; }
+    static bool equal(Key lhs, Key rhs) { return ats_ip_addr_port_eq(lhs, 
rhs); }
+  };
+
+  /// Interface class for FQDN map.
+  struct HostHashing
+  {
+    typedef uint64_t ID;
+    typedef INK_MD5 const& Key;
+    typedef HttpServerSession Value;
+    typedef DList(HttpServerSession, host_hash_link) ListHead;
+
+    static ID hash(Key key) { return key.fold(); }
+    static Key key(Value const* value) { return value->hostname_hash; } 
+    static bool equal(Key lhs, Key rhs) { return lhs == rhs; }
+  };
+
+  typedef TSHashTable<IPHashing> IPHashTable; ///< Sessions by IP address.
+  typedef TSHashTable<HostHashing> HostHashTable; ///< Sessions by host name.
+
+public:
+  /** Check if a session matches address and host name.
+   */
+  static bool match(HttpServerSession* ss, sockaddr const* addr, INK_MD5 
const& host_hash, TSServerSessionSharingMatchType match_style);
+
+  /** Get a session from the pool.
+
+      The session is selected based on @a match_style equivalently to @a 
match. If found the session
+      is removed from the pool.
+
+      @return A pointer to the session or @c NULL if not matching session was 
found.
+  */
+  HttpServerSession* acquireSession(sockaddr const* addr, INK_MD5 const& 
host_hash, TSServerSessionSharingMatchType match_style);
+  /** Release a session to to pool.
+   */
+  void releaseSession(HttpServerSession* ss);
+
+  /// Close all sessions and then clear the table.
+  void purge();
+
+  // Pools of server sessions.
+  // Note that each server session is stored in both pools.
+  IPHashTable m_ip_pool;
+  HostHashTable m_host_pool;
 };
 
 enum HSMresult_t
@@ -65,7 +127,7 @@ enum HSMresult_t
 class HttpSessionManager
 {
 public:
-  HttpSessionManager()
+  HttpSessionManager() : m_g_pool(NULL)
   { }
 
   ~HttpSessionManager()
@@ -78,26 +140,10 @@ public:
   void init();
   int main_handler(int event, void *data);
 
-  /// Check if a session is a valid match.
-  static bool match(
-                   HttpServerSession* s, ///< Session to check for match.
-                   sockaddr const* addr, ///< IP address.
-                   INK_MD5 const& hostname_hash, ///< Hash of hostname of 
origin server.
-                   HttpSM* sm ///< State machine (for configuration data).
-                   );
-
-  /// Check if a session is a valid match.
-  static bool match(
-                   HttpServerSession* s, ///< Session to check for match.
-                   sockaddr const* addr, ///< IP address.
-                   char const* hostname, ///< Hostname of origin server.
-                   HttpSM* sm ///< State machine (for configuration data).
-                   );
-
-
 private:
-  //    Global l1 hash, used when there is no per-thread buckets
-  SessionBucket g_l1_hash[HSM_LEVEL1_BUCKETS];
+  /// Global pool, used if not per thread pools.
+  /// @internal We delay creating this because the session manager is created 
during global statics init.
+  ServerSessionPool* m_g_pool;
 };
 
 extern HttpSessionManager httpSessionManager;

Reply via email to