You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2019/02/19 12:55:20 UTC

[trafficserver] branch master updated: RecHttp: Convert protocol session pool to use views and MemArena.

This is an automated email from the ASF dual-hosted git repository.

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 5ad8eec  RecHttp: Convert protocol session pool to use views and MemArena.
5ad8eec is described below

commit 5ad8eec303b5f9c38da0de3775e0aadb7186fc38
Author: Alan M. Carroll <am...@apache.org>
AuthorDate: Thu Feb 14 15:06:58 2019 -0600

    RecHttp: Convert protocol session pool to use views and MemArena.
---
 lib/records/I_RecHttp.h | 72 ++++++++++++++++++++++++-------------------------
 lib/records/RecHttp.cc  | 58 ++++++++++++++++-----------------------
 2 files changed, 58 insertions(+), 72 deletions(-)

diff --git a/lib/records/I_RecHttp.h b/lib/records/I_RecHttp.h
index 1c95ef7..c3db5a7 100644
--- a/lib/records/I_RecHttp.h
+++ b/lib/records/I_RecHttp.h
@@ -29,8 +29,9 @@
 #include "ts/apidefs.h"
 #include "tscore/ink_assert.h"
 #include "tscore/IpMap.h"
+#include "tscore/MemArena.h"
 #include <algorithm>
-#include <vector>
+#include <array>
 
 /// Load default inbound IP addresses from the configuration file.
 void RecHttpLoadIp(const char *name, ///< Name of value in configuration file.
@@ -48,18 +49,17 @@ void RecHttpLoadIpMap(const char *name, ///< Name of value in configuration file
 */
 class SessionProtocolSet
 {
-  typedef SessionProtocolSet self; ///< Self reference type.
+  using self_type = SessionProtocolSet; ///< Self reference type.
   /// Storage for the set - a bit vector.
-  uint32_t m_bits;
+  uint32_t m_bits = 0;
 
 public:
-  // The right way.
-  //  static int const MAX = sizeof(m_bits) * CHAR_BIT;
-  // The RHEL5/gcc 4.1.2 way
-  static int const MAX = sizeof(uint32_t) * 8;
+  static constexpr int MAX = sizeof(m_bits) * CHAR_BIT;
+
   /// Default constructor.
   /// Constructs and empty set.
-  SessionProtocolSet() : m_bits(0) {}
+  SessionProtocolSet() = default;
+
   uint32_t
   indexToMask(int idx) const
   {
@@ -72,9 +72,10 @@ public:
   {
     m_bits |= this->indexToMask(idx);
   }
+
   /// Mark all the protocols in @a that as present in @a this.
   void
-  markIn(self const &that)
+  markIn(self_type const &that)
   {
     m_bits |= that.m_bits;
   }
@@ -86,7 +87,7 @@ public:
   }
   /// Mark the protocols in @a that as not in @a this.
   void
-  markOut(self const &that)
+  markOut(self_type const &that)
   {
     m_bits &= ~(that.m_bits);
   }
@@ -98,7 +99,7 @@ public:
   }
   /// Test if all the protocols in @a that are in @a this protocol set.
   bool
-  contains(self const &that) const
+  contains(self_type const &that) const
   {
     return that.m_bits == (that.m_bits & m_bits);
   }
@@ -117,7 +118,7 @@ public:
 
   /// Check for intersection.
   bool
-  intersects(self const &that)
+  intersects(self_type const &that)
   {
     return 0 != (m_bits & that.m_bits);
   }
@@ -131,7 +132,7 @@ public:
 
   /// Equality (identical sets).
   bool
-  operator==(self const &that) const
+  operator==(self_type const &that) const
   {
     return m_bits == that.m_bits;
   }
@@ -147,52 +148,51 @@ const char *RecNormalizeProtoTag(const char *tag);
 
 /** Registered session protocol names.
 
-    We do this to avoid lots of string compares. By normalizing the
-    string names we can just compare their indices in this table.
+    We do this to avoid lots of string compares. By normalizing the string names we can just compare
+    their indices in this table.
+
+    @internal To simplify the implementation we limit the maximum number of strings to 32. That will
+    be sufficient for the forseeable future. We can come back to this if it ever becomes a problem.
 
-    @internal To simplify the implementation we limit the maximum
-    number of strings to 32. That will be sufficient for the forseeable
-    future. We can come back to this if it ever becomes a problem.
+    @internal Because we have so few strings we just use a linear search. If the size gets much
+    larger we should consider doing something more clever.
 
-    @internal Because we have so few strings we just use a linear search.
-    If the size gets much larger we should consider doing something more
-    clever.
+    @internal This supports providing constant strings because those strings are exported to the
+    C API and this logic @b must return exactly those pointers.
 */
 class SessionProtocolNameRegistry
 {
 public:
-  static int const MAX     = SessionProtocolSet::MAX; ///< Maximum # of registered names.
-  static int const INVALID = -1;                      ///< Normalized invalid index value.
+  static int constexpr MAX     = SessionProtocolSet::MAX; ///< Maximum # of registered names.
+  static int constexpr INVALID = -1;                      ///< Normalized invalid index value.
+
+  using TextView = ts::TextView;
 
   /// Default constructor.
   /// Creates empty registry with no names.
-  SessionProtocolNameRegistry();
-
-  /// Destructor.
-  /// Cleans up strings.
-  ~SessionProtocolNameRegistry();
+  SessionProtocolNameRegistry() = default;
 
   /** Get the index for @a name, registering it if needed.
       The name is copied internally.
       @return The index for the registered @a name.
   */
-  int toIndex(const char *name);
+  int toIndex(TextView name);
 
   /** Get the index for @a name, registering it if needed.
       The caller @b guarantees @a name is persistent and immutable.
       @return The index for the registered @a name.
   */
-  int toIndexConst(const char *name);
+  int toIndexConst(TextView name);
 
   /** Convert a @a name to an index.
       @return The index for @a name or @c INVALID if it is not registered.
   */
-  int indexFor(const char *name) const;
+  int indexFor(TextView name) const;
 
   /** Convert an @a index to the corresponding name.
       @return A pointer to the name or @c nullptr if the index isn't registered.
   */
-  const char *nameFor(int index) const;
+  TextView nameFor(int index) const;
 
   /// Mark protocols as present in @a sp_set based on the names in @a value.
   /// The names can be separated by ;/|,: and space.
@@ -201,11 +201,9 @@ public:
   void markIn(const char *value, SessionProtocolSet &sp_set);
 
 protected:
-  unsigned int m_n;         ///< Index of first unused slot.
-  const char *m_names[MAX]; ///< Pointers to registered names.
-  uint8_t m_flags[MAX];     ///< Flags for each name.
-
-  static uint8_t const F_ALLOCATED = 0x1; ///< Flag for allocated by this instance.
+  int m_n = 0; ///< Index of first unused slot.
+  std::array<TextView, MAX> m_names;
+  ts::MemArena m_arena; ///< Storage for non-constant strings.
 };
 
 extern SessionProtocolNameRegistry globalSessionProtocolNameRegistry;
diff --git a/lib/records/RecHttp.cc b/lib/records/RecHttp.cc
index 64193b8..d20ab3a 100644
--- a/lib/records/RecHttp.cc
+++ b/lib/records/RecHttp.cc
@@ -500,7 +500,7 @@ SessionProtocolNameRegistry::markIn(const char *value, SessionProtocolSet &sp_se
     } else if (0 == strcasecmp(elt, TS_ALPN_PROTOCOL_GROUP_HTTP2)) {
       sp_set.markIn(HTTP2_PROTOCOL_SET);
     } else { // user defined - register and mark.
-      int idx = globalSessionProtocolNameRegistry.toIndex(elt);
+      int idx = globalSessionProtocolNameRegistry.toIndex(TextView{elt, strlen(elt)});
       sp_set.markIn(idx);
     }
   }
@@ -651,7 +651,8 @@ HttpProxyPort::print(char *out, size_t n)
     bool sep_p = !need_colon_p;
     for (int k = 0; k < SessionProtocolSet::MAX; ++k) {
       if (sp_set.contains(k)) {
-        zret += snprintf(out + zret, n - zret, "%s%s", sep_p ? ";" : "", globalSessionProtocolNameRegistry.nameFor(k));
+        auto name{globalSessionProtocolNameRegistry.nameFor(k)};
+        zret += snprintf(out + zret, n - zret, "%s%.*s", sep_p ? ";" : "", static_cast<int>(name.size()), name.data());
         sep_p = true;
       }
     }
@@ -678,10 +679,10 @@ void
 ts_session_protocol_well_known_name_indices_init()
 {
   // register all the well known protocols and get the indices set.
-  TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_0_9);
-  TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_0);
-  TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_1_1);
-  TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(TS_ALPN_PROTOCOL_HTTP_2_0);
+  TS_ALPN_PROTOCOL_INDEX_HTTP_0_9 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_0_9});
+  TS_ALPN_PROTOCOL_INDEX_HTTP_1_0 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_1_0});
+  TS_ALPN_PROTOCOL_INDEX_HTTP_1_1 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_1_1});
+  TS_ALPN_PROTOCOL_INDEX_HTTP_2_0 = globalSessionProtocolNameRegistry.toIndexConst(std::string_view{TS_ALPN_PROTOCOL_HTTP_2_0});
 
   // Now do the predefined protocol sets.
   HTTP_PROTOCOL_SET.markIn(TS_ALPN_PROTOCOL_INDEX_HTTP_0_9);
@@ -713,30 +714,18 @@ RecNormalizeProtoTag(const char *tag)
   return findResult == TSProtoTags.end() ? nullptr : findResult->data();
 }
 
-SessionProtocolNameRegistry::SessionProtocolNameRegistry() : m_n(0)
-{
-  memset(m_names, 0, sizeof(m_names));
-  memset(&m_flags, 0, sizeof(m_flags));
-}
-
-SessionProtocolNameRegistry::~SessionProtocolNameRegistry()
-{
-  for (size_t i = 0; i < m_n; ++i) {
-    if (m_flags[i] & F_ALLOCATED) {
-      ats_free(const_cast<char *>(m_names[i])); // blech - ats_free won't take a const char*
-    }
-  }
-}
-
 int
-SessionProtocolNameRegistry::toIndex(const char *name)
+SessionProtocolNameRegistry::toIndex(ts::TextView name)
 {
   int zret = this->indexFor(name);
   if (INVALID == zret) {
-    if (m_n < static_cast<size_t>(MAX)) {
-      m_names[m_n] = ats_strdup(name);
-      m_flags[m_n] = F_ALLOCATED;
-      zret         = m_n++;
+    if (m_n < MAX) {
+      // Localize the name by copying it in to the arena.
+      auto text = m_arena.alloc(name.size() + 1);
+      memcpy(text.data(), name.data(), name.size());
+      text.end()[-1] = '\0';
+      m_names[m_n]   = text.view();
+      zret           = m_n++;
     } else {
       ink_release_assert(!"Session protocol name registry overflow");
     }
@@ -745,11 +734,11 @@ SessionProtocolNameRegistry::toIndex(const char *name)
 }
 
 int
-SessionProtocolNameRegistry::toIndexConst(const char *name)
+SessionProtocolNameRegistry::toIndexConst(TextView name)
 {
   int zret = this->indexFor(name);
   if (INVALID == zret) {
-    if (m_n < static_cast<size_t>(MAX)) {
+    if (m_n < MAX) {
       m_names[m_n] = name;
       zret         = m_n++;
     } else {
@@ -760,18 +749,17 @@ SessionProtocolNameRegistry::toIndexConst(const char *name)
 }
 
 int
-SessionProtocolNameRegistry::indexFor(const char *name) const
+SessionProtocolNameRegistry::indexFor(TextView name) const
 {
-  for (size_t i = 0; i < m_n; ++i) {
-    if (0 == strcasecmp(name, m_names[i])) {
-      return i;
-    }
+  auto spot = std::find(m_names.begin(), m_names.begin() + m_n, name);
+  if (spot != m_names.end()) {
+    return static_cast<int>(spot - m_names.begin());
   }
   return INVALID;
 }
 
-const char *
+ts::TextView
 SessionProtocolNameRegistry::nameFor(int idx) const
 {
-  return 0 <= idx && idx < static_cast<int>(m_n) ? m_names[idx] : nullptr;
+  return 0 <= idx && idx < m_n ? m_names[idx] : TextView{};
 }