-/*
- * Copyright 2001-2007 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
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
*/
/**
* 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 <log4cpp/Category.hh>
+#include <memory>
#include <xercesc/util/XMLUniDefs.hpp>
+using namespace xmltooling::logging;
using namespace xmltooling;
-using namespace log4cpp;
using namespace std;
+using xercesc::DOMElement;
+
+namespace {
+ // Reasonably extended sizes to avoid callers needing to shrink unduly.
+ static const XMLTOOL_DLLLOCAL StorageService::Capabilities g_memCaps(0x4000, 0x4000, 0x4000);
+};
+
namespace xmltooling {
class XMLTOOL_DLLLOCAL MemoryStorageService : public StorageService
{
public:
MemoryStorageService(const DOMElement* e);
virtual ~MemoryStorageService();
-
+
+ const Capabilities& getCapabilities() const {
+ return g_memCaps;
+ }
+
bool 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);
+ 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);
-
+
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) {
}
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) {}
time_t expiration;
int version;
};
-
+
struct XMLTOOL_DLLLOCAL Context {
Context() {}
Context(const Context& src) {
}
map<string,Context> m_contextMap;
- RWLock* m_lock;
- CondWait* shutdown_wait;
- Thread* cleanup_thread;
+ auto_ptr<RWLock> m_lock;
+ auto_ptr<CondWait> shutdown_wait;
+ auto_ptr<Thread> cleanup_thread;
static void* cleanup_fn(void*);
bool shutdown;
int m_cleanupInterval;
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)
- : m_lock(NULL), shutdown_wait(NULL), cleanup_thread(NULL), shutdown(false), m_cleanupInterval(0),
+ : m_lock(RWLock::create()), shutdown_wait(CondWait::create()), shutdown(false),
+ m_cleanupInterval(XMLHelper::getAttrInt(e, 900, cleanupInterval)),
m_log(Category::getInstance(XMLTOOLING_LOGCAT".StorageService"))
{
- const XMLCh* tag=e ? e->getAttributeNS(NULL,cleanupInterval) : NULL;
- if (tag && *tag) {
- m_cleanupInterval = XMLString::parseInt(tag);
- }
- if (!m_cleanupInterval)
- m_cleanupInterval=900;
-
- m_lock = RWLock::create();
- shutdown_wait = CondWait::create();
- cleanup_thread = Thread::create(&cleanup_fn, (void*)this);
+ cleanup_thread.reset(Thread::create(&cleanup_fn, (void*)this));
}
MemoryStorageService::~MemoryStorageService()
// Shut down the cleanup thread and let it know...
shutdown = true;
shutdown_wait->signal();
- cleanup_thread->join(NULL);
-
- delete shutdown_wait;
- delete m_lock;
+ cleanup_thread->join(nullptr);
}
-void* MemoryStorageService::cleanup_fn(void* cache_p)
+void* MemoryStorageService::cleanup_fn(void* pv)
{
- MemoryStorageService* cache = reinterpret_cast<MemoryStorageService*>(cache_p);
+ MemoryStorageService* cache = reinterpret_cast<MemoryStorageService*>(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
auto_ptr<Mutex> 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);
- m_lock->wrlock();
- SharedLock locker(m_lock, false);
- for (map<string,Context>::iterator i=m_contextMap.begin(); i!=m_contextMap.end(); ++i)
+ time_t now = time(nullptr);
+ cache->m_lock->wrlock();
+ SharedLock locker(cache->m_lock.get(), false);
+ for (map<string,Context>::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)
{
Context& ctx = writeContext(context);
- SharedLock locker(m_lock, false);
- ctx.reap(time(NULL));
+ SharedLock locker(m_lock.get(), false);
+ ctx.reap(time(nullptr));
}
unsigned long MemoryStorageService::Context::reap(time_t exp)
bool MemoryStorageService::createString(const char* context, const char* key, const char* value, time_t expiration)
{
Context& ctx = writeContext(context);
- SharedLock locker(m_lock, false);
+ SharedLock locker(m_lock.get(), false);
// Check for a duplicate.
map<string,Record>::iterator i=ctx.m_dataMap.find(key);
if (i!=ctx.m_dataMap.end()) {
// Not yet expired?
- if (time(NULL) < i->second.expiration)
+ 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);
+
+ m_log.debug("inserted record (%s) in context (%s) with expiration (%lu)", key, context, expiration);
return true;
}
int MemoryStorageService::readString(const char* context, const char* key, string* pvalue, time_t* pexpiration, int version)
{
Context& ctx = readContext(context);
- SharedLock locker(m_lock, false);
+ SharedLock locker(m_lock.get(), false);
map<string,Record>::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;
int MemoryStorageService::updateString(const char* context, const char* key, const char* value, time_t expiration, int version)
{
Context& ctx = writeContext(context);
- SharedLock locker(m_lock, false);
+ SharedLock locker(m_lock.get(), false);
map<string,Record>::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
i->second.data = value;
++(i->second.version);
}
-
+
if (expiration && expiration != i->second.expiration)
i->second.expiration = expiration;
- m_log.debug("updated record (%s) in context (%s)", key, context);
+ m_log.debug("updated record (%s) in context (%s) with expiration (%lu)", key, context, i->second.expiration);
return i->second.version;
}
bool MemoryStorageService::deleteString(const char* context, const char* key)
{
Context& ctx = writeContext(context);
- SharedLock locker(m_lock, false);
-
+ SharedLock locker(m_lock.get(), false);
+
// Find the record.
map<string,Record>::iterator i=ctx.m_dataMap.find(key);
if (i!=ctx.m_dataMap.end()) {
void MemoryStorageService::updateContext(const char* context, time_t expiration)
{
Context& ctx = writeContext(context);
- SharedLock locker(m_lock, false);
+ SharedLock locker(m_lock.get(), false);
- time_t now = time(NULL);
+ time_t now = time(nullptr);
map<string,Record>::iterator stop=ctx.m_dataMap.end();
for (map<string,Record>::iterator i = ctx.m_dataMap.begin(); i!=stop; ++i) {
if (now < i->second.expiration)
i->second.expiration = expiration;
}
- m_log.debug("updated expiration of valid records in context (%s)", context);
+ m_log.debug("updated expiration of valid records in context (%s) to (%lu)", context, expiration);
}