X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fimpl%2FMemoryStorageService.cpp;h=7592ce82d2b60bcb848ba4382df81b211685b828;hb=a0d768778a8f5f539b909baf5b115e70ea765f0f;hp=69d4b295fbead6b6251f90a22bd670110233a46b;hpb=000e6abde1a148e0bd84db422897cf9045eca1f0;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/impl/MemoryStorageService.cpp b/xmltooling/impl/MemoryStorageService.cpp index 69d4b29..7592ce8 100644 --- a/xmltooling/impl/MemoryStorageService.cpp +++ b/xmltooling/impl/MemoryStorageService.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2001-2007 Internet2 - * + * Copyright 2001-2010 Internet2 + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,58 +16,60 @@ /** * MemoryStorageService.cpp - * + * * In-memory "persistent" storage, suitable for simple applications. */ #include "internal.h" +#include "logging.h" #include "util/NDC.h" #include "util/StorageService.h" #include "util/Threads.h" #include "util/XMLHelper.h" -#include +#include #include +using namespace xmltooling::logging; using namespace xmltooling; -using namespace log4cpp; using namespace std; +using xercesc::DOMElement; + namespace xmltooling { class XMLTOOL_DLLLOCAL MemoryStorageService : public StorageService { public: MemoryStorageService(const DOMElement* e); virtual ~MemoryStorageService(); - - void createString(const char* context, const char* key, const char* value, time_t expiration); - int readString(const char* context, const char* key, string* pvalue=NULL, time_t* pexpiration=NULL, int version=0); - int updateString(const char* context, const char* key, const char* value=NULL, time_t expiration=0, int version=0); + + bool createString(const char* context, const char* key, const char* value, time_t expiration); + int readString(const char* context, const char* key, string* pvalue=nullptr, time_t* pexpiration=nullptr, int version=0); + int updateString(const char* context, const char* key, const char* value=nullptr, time_t expiration=0, int version=0); bool deleteString(const char* context, const char* key); - - void createText(const char* context, const char* key, const char* value, time_t expiration) { + + bool createText(const char* context, const char* key, const char* value, time_t expiration) { return createString(context, key, value, expiration); } - int readText(const char* context, const char* key, string* pvalue=NULL, time_t* pexpiration=NULL, int version=0) { + int readText(const char* context, const char* key, string* pvalue=nullptr, time_t* pexpiration=nullptr, int version=0) { return readString(context, key, pvalue, pexpiration, version); } - int updateText(const char* context, const char* key, const char* value=NULL, time_t expiration=0, int version=0) { + int updateText(const char* context, const char* key, const char* value=nullptr, time_t expiration=0, int version=0) { return updateString(context, key, value, expiration, version); } bool deleteText(const char* context, const char* key) { return deleteString(context, key); } - + void reap(const char* context); void updateContext(const char* context, time_t expiration); void deleteContext(const char* context) { - Lock wrapper(contextLock); + m_lock->wrlock(); m_contextMap.erase(context); + m_lock->unlock(); } private: - void cleanup(); - struct XMLTOOL_DLLLOCAL Record { Record() : expiration(0), version(1) {} Record(const string& s, time_t t) : data(s), expiration(t), version(1) {} @@ -75,34 +77,39 @@ namespace xmltooling { time_t expiration; int version; }; - + struct XMLTOOL_DLLLOCAL Context { - Context() : m_lock(RWLock::create()) {} + Context() {} Context(const Context& src) { m_dataMap = src.m_dataMap; - m_lock = RWLock::create(); } - ~Context() { delete m_lock; } map m_dataMap; - RWLock* m_lock; unsigned long reap(time_t exp); }; - Context& getContext(const char* context) { - Lock wrapper(contextLock); + Context& readContext(const char* context) { + m_lock->rdlock(); + map::iterator i = m_contextMap.find(context); + if (i != m_contextMap.end()) + return i->second; + m_lock->unlock(); + m_lock->wrlock(); + return m_contextMap[context]; + } + + Context& writeContext(const char* context) { + m_lock->wrlock(); return m_contextMap[context]; } map m_contextMap; - Mutex* contextLock; + RWLock* m_lock; CondWait* shutdown_wait; Thread* cleanup_thread; static void* cleanup_fn(void*); bool shutdown; int m_cleanupInterval; Category& m_log; - - friend class _expcheck; }; StorageService* XMLTOOL_DLLLOCAL MemoryStorageServiceFactory(const DOMElement* const & e) @@ -114,17 +121,17 @@ namespace xmltooling { static const XMLCh cleanupInterval[] = UNICODE_LITERAL_15(c,l,e,a,n,u,p,I,n,t,e,r,v,a,l); MemoryStorageService::MemoryStorageService(const DOMElement* e) - : contextLock(NULL), shutdown_wait(NULL), cleanup_thread(NULL), shutdown(false), m_cleanupInterval(0), + : m_lock(nullptr), shutdown_wait(nullptr), cleanup_thread(nullptr), shutdown(false), m_cleanupInterval(0), m_log(Category::getInstance(XMLTOOLING_LOGCAT".StorageService")) { - const XMLCh* tag=e ? e->getAttributeNS(NULL,cleanupInterval) : NULL; + const XMLCh* tag=e ? e->getAttributeNS(nullptr,cleanupInterval) : nullptr; if (tag && *tag) { m_cleanupInterval = XMLString::parseInt(tag); } if (!m_cleanupInterval) m_cleanupInterval=900; - contextLock = Mutex::create(); + m_lock = RWLock::create(); shutdown_wait = CondWait::create(); cleanup_thread = Thread::create(&cleanup_fn, (void*)this); } @@ -134,28 +141,22 @@ MemoryStorageService::~MemoryStorageService() // Shut down the cleanup thread and let it know... shutdown = true; shutdown_wait->signal(); - cleanup_thread->join(NULL); + cleanup_thread->join(nullptr); + delete cleanup_thread; delete shutdown_wait; - delete contextLock; + delete m_lock; } -void* MemoryStorageService::cleanup_fn(void* cache_p) +void* MemoryStorageService::cleanup_fn(void* pv) { - MemoryStorageService* cache = reinterpret_cast(cache_p); + MemoryStorageService* cache = reinterpret_cast(pv); #ifndef WIN32 - // First, let's block all signals + // First, let's block all signals Thread::mask_all_signals(); #endif - // Now run the cleanup process. - cache->cleanup(); - return NULL; -} - -void MemoryStorageService::cleanup() -{ #ifdef _DEBUG NDC ndc("cleanup"); #endif @@ -163,40 +164,39 @@ void MemoryStorageService::cleanup() auto_ptr mutex(Mutex::create()); mutex->lock(); - m_log.info("cleanup thread started...running every %d seconds", m_cleanupInterval); + cache->m_log.info("cleanup thread started...running every %d seconds", cache->m_cleanupInterval); - while (!shutdown) { - shutdown_wait->timedwait(mutex.get(), m_cleanupInterval); - if (shutdown) + while (!cache->shutdown) { + cache->shutdown_wait->timedwait(mutex.get(), cache->m_cleanupInterval); + if (cache->shutdown) break; - + unsigned long count=0; - time_t now = time(NULL); - Lock wrapper(contextLock); - for (map::iterator i=m_contextMap.begin(); i!=m_contextMap.end(); ++i) + time_t now = time(nullptr); + cache->m_lock->wrlock(); + SharedLock locker(cache->m_lock, false); + for (map::iterator i=cache->m_contextMap.begin(); i!=cache->m_contextMap.end(); ++i) count += i->second.reap(now); - + if (count) - m_log.info("purged %d expired record(s) from storage", count); + cache->m_log.info("purged %d expired record(s) from storage", count); } - m_log.info("cleanup thread finished"); + cache->m_log.info("cleanup thread finished"); mutex->unlock(); - Thread::exit(NULL); + return nullptr; } void MemoryStorageService::reap(const char* context) { - getContext(context).reap(time(NULL)); + Context& ctx = writeContext(context); + SharedLock locker(m_lock, false); + ctx.reap(time(nullptr)); } unsigned long MemoryStorageService::Context::reap(time_t exp) { - // Lock the "database". - m_lock->wrlock(); - SharedLock wrapper(m_lock, false); - // Garbage collect any expired entries. unsigned long count=0; map::iterator cur = m_dataMap.begin(); @@ -214,38 +214,36 @@ unsigned long MemoryStorageService::Context::reap(time_t exp) return count; } -void MemoryStorageService::createString(const char* context, const char* key, const char* value, time_t expiration) +bool MemoryStorageService::createString(const char* context, const char* key, const char* value, time_t expiration) { - Context& ctx = getContext(context); + Context& ctx = writeContext(context); + SharedLock locker(m_lock, false); - // Lock the maps. - ctx.m_lock->wrlock(); - SharedLock wrapper(ctx.m_lock, false); - // Check for a duplicate. map::iterator i=ctx.m_dataMap.find(key); if (i!=ctx.m_dataMap.end()) { // Not yet expired? - if (time(NULL) < i->second.expiration) - throw IOException("attempted to insert a record with duplicate key ($1)", params(1,key)); + if (time(nullptr) < i->second.expiration) + return false; // It's dead, so we can just remove it now and create the new record. ctx.m_dataMap.erase(i); } - + ctx.m_dataMap[key]=Record(value,expiration); - + m_log.debug("inserted record (%s) in context (%s)", key, context); + return true; } int MemoryStorageService::readString(const char* context, const char* key, string* pvalue, time_t* pexpiration, int version) { - Context& ctx = getContext(context); + Context& ctx = readContext(context); + SharedLock locker(m_lock, false); - SharedLock wrapper(ctx.m_lock); map::iterator i=ctx.m_dataMap.find(key); if (i==ctx.m_dataMap.end()) return 0; - else if (time(NULL) >= i->second.expiration) + else if (time(nullptr) >= i->second.expiration) return 0; if (pexpiration) *pexpiration = i->second.expiration; @@ -258,18 +256,15 @@ int MemoryStorageService::readString(const char* context, const char* key, strin int MemoryStorageService::updateString(const char* context, const char* key, const char* value, time_t expiration, int version) { - Context& ctx = getContext(context); - - // Lock the map. - ctx.m_lock->wrlock(); - SharedLock wrapper(ctx.m_lock, false); + Context& ctx = writeContext(context); + SharedLock locker(m_lock, false); map::iterator i=ctx.m_dataMap.find(key); if (i==ctx.m_dataMap.end()) return 0; - else if (time(NULL) >= i->second.expiration) + else if (time(nullptr) >= i->second.expiration) return 0; - + if (version > 0 && version != i->second.version) return -1; // caller's out of sync @@ -277,7 +272,7 @@ int MemoryStorageService::updateString(const char* context, const char* key, con i->second.data = value; ++(i->second.version); } - + if (expiration && expiration != i->second.expiration) i->second.expiration = expiration; @@ -287,12 +282,9 @@ int MemoryStorageService::updateString(const char* context, const char* key, con bool MemoryStorageService::deleteString(const char* context, const char* key) { - Context& ctx = getContext(context); + Context& ctx = writeContext(context); + SharedLock locker(m_lock, false); - // Lock the map. - ctx.m_lock->wrlock(); - SharedLock wrapper(ctx.m_lock, false); - // Find the record. map::iterator i=ctx.m_dataMap.find(key); if (i!=ctx.m_dataMap.end()) { @@ -307,16 +299,13 @@ bool MemoryStorageService::deleteString(const char* context, const char* key) void MemoryStorageService::updateContext(const char* context, time_t expiration) { - Context& ctx = getContext(context); - - // Lock the map. - ctx.m_lock->wrlock(); - SharedLock wrapper(ctx.m_lock, false); + Context& ctx = writeContext(context); + SharedLock locker(m_lock, false); - time_t now = time(NULL); + time_t now = time(nullptr); map::iterator stop=ctx.m_dataMap.end(); for (map::iterator i = ctx.m_dataMap.begin(); i!=stop; ++i) { - if (now >= i->second.expiration) + if (now < i->second.expiration) i->second.expiration = expiration; }