Reducing header overuse, non-inlining selected methods (CPPOST-35).
[shibboleth/cpp-sp.git] / memcache-store / memcache-store.cpp
index ac1a8a7..192b197 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- *  Copyright 2001-2008 Internet2\r
+ *  Copyright 2001-2009 Internet2\r
  * \r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -35,6 +35,9 @@
 #endif\r
 \r
 #include <xmltooling/base.h>\r
+\r
+#include <list>\r
+#include <iostream> \r
 #include <libmemcached/memcached.h>\r
 #include <xercesc/util/XMLUniDefs.hpp>\r
 \r
@@ -42,6 +45,7 @@
 #include <xmltooling/XMLToolingConfig.h>\r
 #include <xmltooling/util/NDC.h>\r
 #include <xmltooling/util/StorageService.h>\r
+#include <xmltooling/util/Threads.h>\r
 #include <xmltooling/util/XMLHelper.h>\r
 \r
 using namespace xmltooling::logging;\r
@@ -107,7 +111,7 @@ namespace xmltooling {
     memcached_st *memc;\r
     string m_memcacheHosts;\r
     string m_prefix;\r
-    \r
+    Mutex* m_lock;\r
   };\r
   \r
   class MemcacheStorageService : public StorageService, public MemcacheBase {\r
@@ -158,7 +162,7 @@ bool MemcacheBase::addLock(string what, bool use_prefix) {
   string set_val = "1";\r
   unsigned tries = 5;\r
   while (!addMemcache(lock_name.c_str(), set_val, 5, 0, use_prefix)) {\r
-    if (tries-- < 0) {\r
+    if (tries-- == 0) {\r
       log.debug("Unable to get lock %s... FAILED.", lock_name.c_str());\r
       return false;\r
     }\r
@@ -275,7 +279,6 @@ bool MemcacheBase::deleteMemcache(const char *key,
                                   bool use_prefix) {\r
   memcached_return rv;\r
   string final_key;\r
-  memcached_st clone;\r
   bool success;\r
 \r
   if (use_prefix) {\r
@@ -284,23 +287,25 @@ bool MemcacheBase::deleteMemcache(const char *key,
     final_key = key;\r
   }\r
 \r
-  if (memcached_clone(&clone, memc) == NULL) {\r
-    throw IOException("MemcacheBase::deleteMemcache(): memcached_clone() failed");\r
-  }\r
+  m_lock->lock();\r
+  rv = memcached_delete(memc, (char *)final_key.c_str(), final_key.length(), timeout);\r
+  m_lock->unlock();\r
 \r
-  rv = memcached_delete(&clone, (char *)final_key.c_str(), final_key.length(), timeout);\r
   if (rv == MEMCACHED_SUCCESS) {\r
     success = true;\r
   } else if (rv == MEMCACHED_NOTFOUND) {\r
     // Key wasn't there... No biggie.\r
     success = false;\r
+  } else if (rv == MEMCACHED_ERRNO) {\r
+    // System error\r
+    log.error(string("Memcache::deleteMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno)));\r
+    success = false;\r
   } else {\r
-    log.error(string("Memcache::deleteMemcache() Problems: ") + memcached_strerror(&clone, rv));\r
+    log.error(string("Memcache::deleteMemcache() Problems: ") + memcached_strerror(memc, rv));\r
     // shouldn't be here\r
     success = false;\r
   }\r
 \r
-  memcached_free(&clone);\r
   return success;\r
 }\r
 \r
@@ -312,7 +317,6 @@ bool MemcacheBase::getMemcache(const char *key,
   size_t len;\r
   char *result;\r
   string final_key;\r
-  memcached_st clone;\r
   bool success;\r
   \r
   if (use_prefix) {\r
@@ -321,11 +325,10 @@ bool MemcacheBase::getMemcache(const char *key,
     final_key = key;\r
   }\r
 \r
-  if (memcached_clone(&clone, memc) == NULL) {\r
-    throw IOException("MemcacheBase::getMemcache(): memcached_clone() failed");\r
-  }\r
+  m_lock->lock();\r
+  result = memcached_get(memc, (char *)final_key.c_str(), final_key.length(), &len, flags, &rv);\r
+  m_lock->unlock();\r
 \r
-  result = memcached_get(&clone, (char *)final_key.c_str(), final_key.length(), &len, flags, &rv);\r
   if (rv == MEMCACHED_SUCCESS) {\r
     dest = result;\r
     free(result);\r
@@ -333,12 +336,15 @@ bool MemcacheBase::getMemcache(const char *key,
   } else if (rv == MEMCACHED_NOTFOUND) {\r
     log.debug("Key %s not found in memcache...", key);\r
     success = false;\r
+  } else if (rv == MEMCACHED_ERRNO) {\r
+    // System error\r
+    log.error(string("Memcache::getMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno)));\r
+    success = false;\r
   } else {\r
-    log.error(string("Memcache::getMemcache() Problems: ") + memcached_strerror(&clone, rv));\r
+    log.error(string("Memcache::getMemcache() Problems: ") + memcached_strerror(memc, rv));\r
     success = false;\r
   }\r
 \r
-  memcached_free(&clone);\r
   return success;\r
 }\r
 \r
@@ -350,7 +356,6 @@ bool MemcacheBase::addMemcache(const char *key,
 \r
   memcached_return rv;\r
   string final_key;\r
-  memcached_st clone;\r
   bool success;\r
 \r
   if (use_prefix) {\r
@@ -359,23 +364,25 @@ bool MemcacheBase::addMemcache(const char *key,
     final_key = key;\r
   }\r
 \r
-  if (memcached_clone(&clone, memc) == NULL) {\r
-    throw IOException("MemcacheBase::addMemcache(): memcached_clone() failed");\r
-  }\r
+  m_lock->lock();\r
+  rv = memcached_add(memc, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);\r
+  m_lock->unlock();\r
 \r
-  rv = memcached_add(&clone, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);\r
   if (rv == MEMCACHED_SUCCESS) {\r
     success = true;\r
   } else if (rv == MEMCACHED_NOTSTORED) {\r
     // already there\r
     success = false;\r
+  } else if (rv == MEMCACHED_ERRNO) {\r
+    // System error\r
+    log.error(string("Memcache::addMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno)));\r
+    success = false;\r
   } else {\r
     // shouldn't be here\r
-    log.error(string("Memcache::addMemcache() Problems: ") + memcached_strerror(&clone, rv));\r
+    log.error(string("Memcache::addMemcache() Problems: ") + memcached_strerror(memc, rv));\r
     success = false;\r
   }\r
 \r
-  memcached_free(&clone);\r
   return success;\r
 }\r
 \r
@@ -387,7 +394,6 @@ bool MemcacheBase::setMemcache(const char *key,
 \r
   memcached_return rv;\r
   string final_key;\r
-  memcached_st clone;\r
   bool success;\r
 \r
   if (use_prefix) {\r
@@ -396,20 +402,22 @@ bool MemcacheBase::setMemcache(const char *key,
     final_key = key;\r
   }\r
 \r
-  if (memcached_clone(&clone, memc) == NULL) {\r
-    throw IOException("MemcacheBase::setMemcache(): memcached_clone() failed");\r
-  }\r
+  m_lock->lock();\r
+  rv = memcached_set(memc, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);\r
+  m_lock->unlock();\r
 \r
-  rv = memcached_set(&clone, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);\r
   if (rv == MEMCACHED_SUCCESS) {\r
     success = true;\r
+  } else if (rv == MEMCACHED_ERRNO) {\r
+    // System error\r
+    log.error(string("Memcache::setMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno)));\r
+    success = false;\r
   } else {\r
     // shouldn't be here\r
-    log.error(string("Memcache::setMemcache() Problems: ") + memcached_strerror(&clone, rv));\r
+    log.error(string("Memcache::setMemcache() Problems: ") + memcached_strerror(memc, rv));\r
     success = false;\r
   }\r
 \r
-  memcached_free(&clone);\r
   return success;\r
 }\r
 \r
@@ -421,7 +429,6 @@ bool MemcacheBase::replaceMemcache(const char *key,
   \r
   memcached_return rv;\r
   string final_key;\r
-  memcached_st clone;\r
   bool success;\r
 \r
   if (use_prefix) {\r
@@ -430,23 +437,25 @@ bool MemcacheBase::replaceMemcache(const char *key,
     final_key = key;\r
   }\r
 \r
-  if (memcached_clone(&clone, memc) == NULL) {\r
-    throw IOException("MemcacheBase::replaceMemcache(): memcached_clone() failed");\r
-  }\r
+  m_lock->lock();\r
+  rv = memcached_replace(memc, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);\r
+  m_lock->unlock();\r
 \r
-  rv = memcached_replace(&clone, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);\r
   if (rv == MEMCACHED_SUCCESS) {\r
     success = true;\r
   } else if (rv == MEMCACHED_NOTSTORED) {\r
     // not there\r
     success = false;\r
+  } else if (rv == MEMCACHED_ERRNO) {\r
+    // System error\r
+    log.error(string("Memcache::replaceMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno)));\r
+    success = false;\r
   } else {\r
     // shouldn't be here\r
-    log.error(string("Memcache::replaceMemcache() Problems: ") + memcached_strerror(&clone, rv));\r
+    log.error(string("Memcache::replaceMemcache() Problems: ") + memcached_strerror(memc, rv));\r
     success = false;\r
   }\r
 \r
-  memcached_free(&clone);\r
   return success;\r
 }\r
 \r
@@ -467,6 +476,9 @@ MemcacheBase::MemcacheBase(const DOMElement* e) : m_root(e), log(Category::getIn
   log.debug("INIT: GOT Hosts: %s", h.get());\r
   m_memcacheHosts = h.get();\r
 \r
+  m_lock = Mutex::create();\r
+  log.debug("Lock created");\r
+\r
   memc = memcached_create(NULL);\r
   if (memc == NULL) {\r
     throw XMLToolingException("MemcacheBase::Memcache(): memcached_create() failed");\r
@@ -474,10 +486,23 @@ MemcacheBase::MemcacheBase(const DOMElement* e) : m_root(e), log(Category::getIn
 \r
   log.debug("Memcache created");\r
 \r
-  unsigned int set = MEMCACHED_HASH_CRC;\r
-  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, set);\r
+  unsigned int hash = MEMCACHED_HASH_CRC;\r
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, hash);\r
   log.debug("CRC hash set");\r
 \r
+  int32_t timeout = 1000000;\r
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SND_TIMEOUT, timeout);\r
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, timeout);\r
+\r
+  int32_t poll_timeout = 1000;\r
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, poll_timeout);\r
+\r
+  int32_t fail_limit = 5;\r
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, fail_limit);\r
+\r
+  int32_t retry_timeout = 30;\r
+  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, retry_timeout);\r
+\r
   memcached_server_st *servers;\r
   servers = memcached_servers_parse((char *)m_memcacheHosts.c_str());\r
   log.debug("Got %u hosts.",  memcached_server_list_count(servers));\r
@@ -491,6 +516,7 @@ MemcacheBase::MemcacheBase(const DOMElement* e) : m_root(e), log(Category::getIn
 \r
 MemcacheBase::~MemcacheBase() {\r
   memcached_free(memc);\r
+  delete m_lock;\r
   log.debug("Base object destroyed");\r
 }\r
 \r
@@ -575,6 +601,19 @@ int MemcacheStorageService::readString(const char* context, const char* key, str
   uint32_t rec_version;\r
   string value;\r
 \r
+  if (m_buildMap) {\r
+    log.debug("Checking context");\r
+\r
+    string map_name = context;\r
+    string ser_arr;\r
+    uint32_t flags;\r
+    bool ctx_found = getMemcache(map_name.c_str(), ser_arr, &flags);\r
+\r
+    if (!ctx_found) {\r
+      return 0;\r
+    }\r
+  }\r
+\r
   bool found = getMemcache(final_key.c_str(), value, &rec_version);\r
   if (!found) {\r
     return 0;\r
@@ -656,12 +695,6 @@ void MemcacheStorageService::updateContext(const char* context, time_t expiratio
   }\r
 \r
   string map_name = context;\r
-  \r
-  if (! addLock(map_name)) {\r
-    log.error("Unable to get lock for context %s!", context);\r
-    return;\r
-  }\r
-  \r
   string ser_arr;\r
   uint32_t flags;\r
   bool result = getMemcache(map_name.c_str(), ser_arr, &flags);\r
@@ -692,8 +725,6 @@ void MemcacheStorageService::updateContext(const char* context, time_t expiratio
     replaceMemcache(map_name.c_str(), ser_arr, expiration, flags);\r
   }\r
   \r
-  deleteLock(map_name);\r
-  \r
 }\r
 \r
 void MemcacheStorageService::deleteContext(const char* context) {\r
@@ -706,12 +737,6 @@ void MemcacheStorageService::deleteContext(const char* context) {
   }\r
 \r
   string map_name = context;\r
-  \r
-  if (! addLock(map_name)) {\r
-    log.error("Unable to get lock for context %s!", context);\r
-    return;\r
-  }\r
-  \r
   string ser_arr;\r
   uint32_t flags;\r
   bool result = getMemcache(map_name.c_str(), ser_arr, &flags);\r
@@ -734,8 +759,6 @@ void MemcacheStorageService::deleteContext(const char* context) {
     deleteMemcache(map_name.c_str(), 0);\r
   }\r
   \r
-  deleteLock(map_name);\r
-\r
 }\r
 \r
 extern "C" int MCEXT_EXPORTS xmltooling_extension_init(void*) {\r