virtual ~MemoryStorageService();
void createString(const char* context, const char* key, const char* value, time_t expiration);
- bool readString(const char* context, const char* key, string* pvalue=NULL, time_t* pexpiration=NULL);
- bool updateString(const char* context, const char* key, const char* value=NULL, time_t expiration=0);
+ 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 deleteString(const char* context, const char* key);
void createText(const char* context, const char* key, const char* value, time_t expiration) {
return createString(context, key, value, expiration);
}
- bool readText(const char* context, const char* key, string* pvalue=NULL, time_t* pexpiration=NULL) {
- return readString(context, key, pvalue, pexpiration);
+ int readText(const char* context, const char* key, string* pvalue=NULL, time_t* pexpiration=NULL, int version=0) {
+ return readString(context, key, pvalue, pexpiration, version);
}
- bool updateText(const char* context, const char* key, const char* value=NULL, time_t expiration=0) {
- return updateString(context, key, value, expiration);
+ int updateText(const char* context, const char* key, const char* value=NULL, 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 cleanup();
struct XMLTOOL_DLLLOCAL Record {
- Record() : expiration(0) {}
- Record(string s, time_t t) : data(s), expiration(t) {}
+ Record() : expiration(0), version(1) {}
+ Record(const string& s, time_t t) : data(s), expiration(t), version(1) {}
string data;
time_t expiration;
+ int version;
};
struct XMLTOOL_DLLLOCAL Context {
#ifdef _DEBUG
NDC ndc("cleanup");
#endif
-
- Mutex* mutex = Mutex::create();
+ auto_ptr<Mutex> mutex(Mutex::create());
mutex->lock();
m_log.info("cleanup thread started...running every %d seconds", m_cleanupInterval);
while (!shutdown) {
- shutdown_wait->timedwait(mutex, m_cleanupInterval);
+ shutdown_wait->timedwait(mutex.get(), m_cleanupInterval);
if (shutdown)
break;
m_log.info("cleanup thread finished");
mutex->unlock();
- delete mutex;
Thread::exit(NULL);
}
m_log.debug("inserted record (%s) in context (%s)", key, context);
}
-bool MemoryStorageService::readString(const char* context, const char* key, string* pvalue, time_t* pexpiration)
+int MemoryStorageService::readString(const char* context, const char* key, string* pvalue, time_t* pexpiration, int version)
{
Context& ctx = getContext(context);
SharedLock wrapper(ctx.m_lock);
map<string,Record>::iterator i=ctx.m_dataMap.find(key);
if (i==ctx.m_dataMap.end())
- return false;
+ return 0;
else if (time(NULL) >= i->second.expiration)
- return false;
+ return 0;
+ if (i->second.version == version)
+ return version; // nothing's changed, so just echo back the version
if (pvalue)
*pvalue = i->second.data;
if (pexpiration)
*pexpiration = i->second.expiration;
- return true;
+ return i->second.version;
}
-bool MemoryStorageService::updateString(const char* context, const char* key, const char* value, time_t expiration)
+int MemoryStorageService::updateString(const char* context, const char* key, const char* value, time_t expiration, int version)
{
Context& ctx = getContext(context);
map<string,Record>::iterator i=ctx.m_dataMap.find(key);
if (i==ctx.m_dataMap.end())
- return false;
+ return 0;
else if (time(NULL) >= i->second.expiration)
- return false;
-
- if (value)
+ return 0;
+
+ if (version > 0 && version != i->second.version)
+ return -1; // caller's out of sync
+
+ if (value) {
i->second.data = value;
+ ++(i->second.version);
+ }
if (expiration && expiration != i->second.expiration) {
// Update secondary map.
}
m_log.debug("updated record (%s) in context (%s)", key, context);
- return true;
+ return i->second.version;
}
bool MemoryStorageService::deleteString(const char* context, const char* key)
/**
* Returns an existing "short" record from the storage service.
+ *
+ * <p>The version parameter can be set for "If-Modified-Since" semantics.
*
* @param context a storage context label
* @param key null-terminated unique key of up to 255 bytes
* @param pvalue location in which to return the record value
* @param pexpiration location in which to return the expiration timestamp
- * @return true iff a valid record exists and was returned
+ * @param version if > 0, only copy back data if newer than supplied version
+ * @return the version of the record read back, or 0 if no record exists
*
* @throws IOException raised if errors occur in the read process
*/
- virtual bool readString(const char* context, const char* key, std::string* pvalue=NULL, time_t* pexpiration=NULL)=0;
+ virtual int readString(
+ const char* context, const char* key, std::string* pvalue=NULL, time_t* pexpiration=NULL, int version=0
+ )=0;
/**
* Updates an existing "short" record in the storage service.
* @param key null-terminated unique key of up to 255 bytes
* @param value null-terminated value of up to 255 bytes to store, or NULL to leave alone
* @param expiration a new expiration timestamp, or 0 to leave alone
- * @return true iff the record exists and was updated
+ * @param version if > 0, only update if the current version matches this value
+ * @return the version of the record after update, 0 if no record exists, or -1 if the version
+ * parameter is non-zero and does not match the current version before update (so the caller is out of sync)
*
* @throws IOException raised if errors occur in the update process
*/
- virtual bool updateString(const char* context, const char* key, const char* value=NULL, time_t expiration=0)=0;
+ virtual int updateString(
+ const char* context, const char* key, const char* value=NULL, time_t expiration=0, int version=0
+ )=0;
/**
* Deletes an existing "short" record from the storage service.
/**
* Returns an existing "long" record from the storage service.
+ *
+ * <p>The version parameter can be set for "If-Modified-Since" semantics.
*
* @param context a storage context label
* @param key null-terminated unique key of up to 255 bytes
* @param pvalue location in which to return the record value
* @param pexpiration location in which to return the expiration timestamp
- * @return true iff a valid record exists and was returned
+ * @param version if > 0, only copy back data if newer than supplied version
+ * @return the version of the record read back, or 0 if no record exists
*
* @throws IOException raised if errors occur in the read process
*/
- virtual bool readText(const char* context, const char* key, std::string* pvalue=NULL, time_t* pexpiration=NULL)=0;
+ virtual int readText(
+ const char* context, const char* key, std::string* pvalue=NULL, time_t* pexpiration=NULL, int version=0
+ )=0;
/**
* Updates an existing "long" record in the storage service.
* @param key null-terminated unique key of up to 255 bytes
* @param value null-terminated value of arbitrary length to store, or NULL to leave alone
* @param expiration a new expiration timestamp, or 0 to leave alone
- * @return true iff the record exists and was updated
+ * @param version if > 0, only update if the current version matches this value
+ * @return the version of the record after update, 0 if no record exists, or -1 if the version
+ * parameter is non-zero and does not match the current version before update (so the caller is out of sync)
*
* @throws IOException raised if errors occur in the update process
*/
- virtual bool updateText(const char* context, const char* key, const char* value=NULL, time_t expiration=0)=0;
+ virtual int updateText(
+ const char* context, const char* key, const char* value=NULL, time_t expiration=0, int version=0
+ )=0;
/**
* Deletes an existing "long" record from the storage service.