|
@@ -52,7 +52,7 @@ static void * allocateAndCopy(const void * src, size_t size)
|
|
static StringBuffer & appendExpire(StringBuffer & buffer, unsigned expire)
|
|
static StringBuffer & appendExpire(StringBuffer & buffer, unsigned expire)
|
|
{
|
|
{
|
|
if (expire > 0)
|
|
if (expire > 0)
|
|
- buffer.append(" EX ").append(expire/1000);
|
|
|
|
|
|
+ buffer.append(" PX ").append(expire);
|
|
return buffer;
|
|
return buffer;
|
|
}
|
|
}
|
|
class Reply : public CInterface
|
|
class Reply : public CInterface
|
|
@@ -102,7 +102,7 @@ public :
|
|
|
|
|
|
//-------------------------------LOCKING------------------------------------------------
|
|
//-------------------------------LOCKING------------------------------------------------
|
|
void lockSet(ICodeContext * ctx, const char * key, size32_t valueSize, const char * value, unsigned expire);
|
|
void lockSet(ICodeContext * ctx, const char * key, size32_t valueSize, const char * value, unsigned expire);
|
|
- void lockGet(ICodeContext * ctx, const char * key, size_t & valueSize, char * & value, const char * password);
|
|
|
|
|
|
+ void lockGet(ICodeContext * ctx, const char * key, size_t & valueSize, char * & value, const char * password, unsigned expire);
|
|
void unlock(ICodeContext * ctx, const char * key);
|
|
void unlock(ICodeContext * ctx, const char * key);
|
|
//--------------------------------------------------------------------------------------
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
|
|
@@ -134,10 +134,10 @@ protected :
|
|
|
|
|
|
//-------------------------------LOCKING------------------------------------------------
|
|
//-------------------------------LOCKING------------------------------------------------
|
|
void handleLockOnSet(ICodeContext * ctx, const char * key, const char * value, size_t size, unsigned expire);
|
|
void handleLockOnSet(ICodeContext * ctx, const char * key, const char * value, size_t size, unsigned expire);
|
|
- void handleLockOnGet(ICodeContext * ctx, const char * key, MemoryAttr * retVal, const char * password);
|
|
|
|
|
|
+ void handleLockOnGet(ICodeContext * ctx, const char * key, MemoryAttr * retVal, const char * password, unsigned expire);
|
|
void encodeChannel(StringBuffer & channel, const char * key) const;
|
|
void encodeChannel(StringBuffer & channel, const char * key) const;
|
|
bool noScript(const redisReply * reply) const;
|
|
bool noScript(const redisReply * reply) const;
|
|
- bool lock(ICodeContext * ctx, const char * key, const char * channel);
|
|
|
|
|
|
+ bool lock(ICodeContext * ctx, const char * key, const char * channel, unsigned expire);
|
|
//--------------------------------------------------------------------------------------
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
|
|
protected :
|
|
protected :
|
|
@@ -455,7 +455,7 @@ void Connection::persist(ICodeContext * ctx, const char * key)
|
|
}
|
|
}
|
|
void Connection::expire(ICodeContext * ctx, const char * key, unsigned _expire)
|
|
void Connection::expire(ICodeContext * ctx, const char * key, unsigned _expire)
|
|
{
|
|
{
|
|
- OwnedReply reply = Reply::createReply(redisCommand(context, "EXPIRE %b %u", key, strlen(key), _expire/1000));
|
|
|
|
|
|
+ OwnedReply reply = Reply::createReply(redisCommand(context, "PEXPIRE %b %u", key, strlen(key), _expire));
|
|
assertOnCommandErrorWithKey(reply->query(), "Expire", key);
|
|
assertOnCommandErrorWithKey(reply->query(), "Expire", key);
|
|
}
|
|
}
|
|
bool Connection::exists(ICodeContext * ctx, const char * key)
|
|
bool Connection::exists(ICodeContext * ctx, const char * key)
|
|
@@ -672,16 +672,16 @@ void Connection::lockSet(ICodeContext * ctx, const char * key, size32_t valueSiz
|
|
}
|
|
}
|
|
//-------------------------------------------GET-----------------------------------------
|
|
//-------------------------------------------GET-----------------------------------------
|
|
//--OUTER--
|
|
//--OUTER--
|
|
-void SyncLockRGet(ICodeContext * ctx, const char * options, const char * key, size_t & returnSize, char * & returnValue, unsigned __int64 database, const char * password, unsigned __int64 _timeout)
|
|
|
|
|
|
+void SyncLockRGet(ICodeContext * ctx, const char * options, const char * key, size_t & returnSize, char * & returnValue, unsigned __int64 database, unsigned expire, const char * password, unsigned __int64 _timeout)
|
|
{
|
|
{
|
|
Owned<Connection> master = Connection::createConnection(ctx, options, database, password, _timeout);
|
|
Owned<Connection> master = Connection::createConnection(ctx, options, database, password, _timeout);
|
|
- master->lockGet(ctx, key, returnSize, returnValue, password);
|
|
|
|
|
|
+ master->lockGet(ctx, key, returnSize, returnValue, password, expire);
|
|
}
|
|
}
|
|
//--INNER--
|
|
//--INNER--
|
|
-void Connection::lockGet(ICodeContext * ctx, const char * key, size_t & returnSize, char * & returnValue, const char * password)
|
|
|
|
|
|
+void Connection::lockGet(ICodeContext * ctx, const char * key, size_t & returnSize, char * & returnValue, const char * password, unsigned expire)
|
|
{
|
|
{
|
|
MemoryAttr retVal;
|
|
MemoryAttr retVal;
|
|
- handleLockOnGet(ctx, key, &retVal, password);
|
|
|
|
|
|
+ handleLockOnGet(ctx, key, &retVal, password, expire);
|
|
returnSize = retVal.length();
|
|
returnSize = retVal.length();
|
|
returnValue = reinterpret_cast<char*>(retVal.detach());
|
|
returnValue = reinterpret_cast<char*>(retVal.detach());
|
|
}
|
|
}
|
|
@@ -690,10 +690,10 @@ void Connection::encodeChannel(StringBuffer & channel, const char * key) const
|
|
{
|
|
{
|
|
channel.append(REDIS_LOCK_PREFIX).append("_").append(key).append("_").append(database);
|
|
channel.append(REDIS_LOCK_PREFIX).append("_").append(key).append("_").append(database);
|
|
}
|
|
}
|
|
-bool Connection::lock(ICodeContext * ctx, const char * key, const char * channel)
|
|
|
|
|
|
+bool Connection::lock(ICodeContext * ctx, const char * key, const char * channel, unsigned expire)
|
|
{
|
|
{
|
|
- StringBuffer cmd("SET %b %b NX EX ");
|
|
|
|
- cmd.append(timeout/1000);
|
|
|
|
|
|
+ StringBuffer cmd("SET %b %b NX PX ");
|
|
|
|
+ cmd.append(expire);
|
|
|
|
|
|
OwnedReply reply = Reply::createReply(redisCommand(context, cmd.str(), key, strlen(key), channel, strlen(channel)));
|
|
OwnedReply reply = Reply::createReply(redisCommand(context, cmd.str(), key, strlen(key), channel, strlen(channel)));
|
|
assertOnError(reply->query(), cmd.append(" of the key '").append(key).append("' failed"));
|
|
assertOnError(reply->query(), cmd.append(" of the key '").append(key).append("' failed"));
|
|
@@ -727,7 +727,7 @@ void Connection::unlock(ICodeContext * ctx, const char * key)
|
|
}
|
|
}
|
|
//If the above is aborted, let the lock expire.
|
|
//If the above is aborted, let the lock expire.
|
|
}
|
|
}
|
|
-void Connection::handleLockOnGet(ICodeContext * ctx, const char * key, MemoryAttr * retVal, const char * password)
|
|
|
|
|
|
+void Connection::handleLockOnGet(ICodeContext * ctx, const char * key, MemoryAttr * retVal, const char * password, unsigned expire)
|
|
{
|
|
{
|
|
//NOTE: This routine can only return an empty string under one condition, that which indicates to the caller that the key was successfully locked.
|
|
//NOTE: This routine can only return an empty string under one condition, that which indicates to the caller that the key was successfully locked.
|
|
|
|
|
|
@@ -735,7 +735,7 @@ void Connection::handleLockOnGet(ICodeContext * ctx, const char * key, MemoryAtt
|
|
encodeChannel(channel, key);
|
|
encodeChannel(channel, key);
|
|
|
|
|
|
//Query key and set lock if non existent
|
|
//Query key and set lock if non existent
|
|
- if (lock(ctx, key, channel.str()))
|
|
|
|
|
|
+ if (lock(ctx, key, channel.str(), expire))
|
|
return;
|
|
return;
|
|
|
|
|
|
#if(0)//Test empty string handling by deleting the lock/value, and thus GET returns REDIS_REPLY_NIL as the reply type and an empty string.
|
|
#if(0)//Test empty string handling by deleting the lock/value, and thus GET returns REDIS_REPLY_NIL as the reply type and an empty string.
|
|
@@ -838,18 +838,18 @@ void Connection::handleLockOnSet(ICodeContext * ctx, const char * key, const cha
|
|
replyContainer->setClear((redisReply*)redisCommand(context, "EVALSHA %b %d %b %b %b", luaScriptSHA1, (size_t)40, 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size));
|
|
replyContainer->setClear((redisReply*)redisCommand(context, "EVALSHA %b %d %b %b %b", luaScriptSHA1, (size_t)40, 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size));
|
|
if (noScript(replyContainer->query()))
|
|
if (noScript(replyContainer->query()))
|
|
{
|
|
{
|
|
- const char * luaScript = "redis.call('SET', KEYS[1], ARGV[2]) redis.call('PUBLISH', ARGV[1], ARGV[2]) return";
|
|
|
|
|
|
+ const char * luaScript = "redis.call('SET', KEYS[1], ARGV[2]) redis.call('PUBLISH', ARGV[1], ARGV[2]) return";//NOTE: MUST update luaScriptSHA1 if luaScript is updated!
|
|
replyContainer->setClear((redisReply*)redisCommand(context, "EVAL %b %d %b %b %b", luaScript, strlen(luaScript), 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size));
|
|
replyContainer->setClear((redisReply*)redisCommand(context, "EVAL %b %d %b %b %b", luaScript, strlen(luaScript), 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- const char * luaScriptWithExpireSHA1 = "c68d1706d7dc6342d5fc1d651e238931bd75320d"; //NOTE: update this if luaScriptWithExpire is updated!
|
|
|
|
- replyContainer->setClear((redisReply*)redisCommand(context, "EVALSHA %b %d %b %b %b %d", luaScriptWithExpireSHA1, (size_t)40, 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size, expire/1000));
|
|
|
|
|
|
+ const char * luaScriptWithExpireSHA1 = "6f6bc88ccea7c6853ccc395eaa7abd8cb91fb2d8"; //NOTE: update this if luaScriptWithExpire is updated!
|
|
|
|
+ replyContainer->setClear((redisReply*)redisCommand(context, "EVALSHA %b %d %b %b %b %d", luaScriptWithExpireSHA1, (size_t)40, 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size, expire));
|
|
if (noScript(replyContainer->query()))
|
|
if (noScript(replyContainer->query()))
|
|
{
|
|
{
|
|
- const char * luaScriptWithExpire = "redis.call('SET', KEYS[1], ARGV[2], 'EX', ARGV[3]) redis.call('PUBLISH', ARGV[1], ARGV[2]) return";
|
|
|
|
- replyContainer->setClear((redisReply*)redisCommand(context, "EVAL %b %d %b %b %b %d", luaScriptWithExpire, strlen(luaScriptWithExpire), 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size, expire/1000));
|
|
|
|
|
|
+ const char * luaScriptWithExpire = "redis.call('SET', KEYS[1], ARGV[2], 'PX', ARGV[3]) redis.call('PUBLISH', ARGV[1], ARGV[2]) return";//NOTE: MUST update luaScriptWithExpireSHA1 if luaScriptWithExpire is updated!
|
|
|
|
+ replyContainer->setClear((redisReply*)redisCommand(context, "EVAL %b %d %b %b %b %d", luaScriptWithExpire, strlen(luaScriptWithExpire), 1, key, strlen(key), channel.str(), (size_t)channel.length(), value, size, expire));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
assertOnCommandErrorWithKey(replyContainer->query(), "SET", key);
|
|
assertOnCommandErrorWithKey(replyContainer->query(), "SET", key);
|
|
@@ -916,24 +916,24 @@ ECL_REDIS_API void ECL_REDIS_CALL SyncLockRSetUtf8(ICodeContext * ctx, size32_t
|
|
returnValue = (char*)allocateAndCopy(value, valueSize);
|
|
returnValue = (char*)allocateAndCopy(value, valueSize);
|
|
}
|
|
}
|
|
//-------------------------------------GET----------------------------------------
|
|
//-------------------------------------GET----------------------------------------
|
|
-ECL_REDIS_API void ECL_REDIS_CALL SyncLockRGetStr(ICodeContext * ctx, size32_t & returnSize, char * & returnValue, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout)
|
|
|
|
|
|
+ECL_REDIS_API void ECL_REDIS_CALL SyncLockRGetStr(ICodeContext * ctx, size32_t & returnSize, char * & returnValue, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout, unsigned expire)
|
|
{
|
|
{
|
|
size_t _returnSize;
|
|
size_t _returnSize;
|
|
- SyncLockRGet(ctx, options, key, _returnSize, returnValue, database, password, timeout);
|
|
|
|
|
|
+ SyncLockRGet(ctx, options, key, _returnSize, returnValue, database, expire, password, timeout);
|
|
returnSize = static_cast<size32_t>(_returnSize);
|
|
returnSize = static_cast<size32_t>(_returnSize);
|
|
}
|
|
}
|
|
-ECL_REDIS_API void ECL_REDIS_CALL SyncLockRGetUChar(ICodeContext * ctx, size32_t & returnLength, UChar * & returnValue, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout)
|
|
|
|
|
|
+ECL_REDIS_API void ECL_REDIS_CALL SyncLockRGetUChar(ICodeContext * ctx, size32_t & returnLength, UChar * & returnValue, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout, unsigned expire)
|
|
{
|
|
{
|
|
size_t returnSize;
|
|
size_t returnSize;
|
|
char * _returnValue;
|
|
char * _returnValue;
|
|
- SyncLockRGet(ctx, options, key, returnSize, _returnValue, database, password, timeout);
|
|
|
|
|
|
+ SyncLockRGet(ctx, options, key, returnSize, _returnValue, database, expire, password, timeout);
|
|
returnValue = (UChar*)_returnValue;
|
|
returnValue = (UChar*)_returnValue;
|
|
returnLength = static_cast<size32_t>(returnSize/sizeof(UChar));
|
|
returnLength = static_cast<size32_t>(returnSize/sizeof(UChar));
|
|
}
|
|
}
|
|
-ECL_REDIS_API void ECL_REDIS_CALL SyncLockRGetUtf8(ICodeContext * ctx, size32_t & returnLength, char * & returnValue, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout)
|
|
|
|
|
|
+ECL_REDIS_API void ECL_REDIS_CALL SyncLockRGetUtf8(ICodeContext * ctx, size32_t & returnLength, char * & returnValue, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout, unsigned expire)
|
|
{
|
|
{
|
|
size_t returnSize;
|
|
size_t returnSize;
|
|
- SyncLockRGet(ctx, options, key, returnSize, returnValue, database, password, timeout);
|
|
|
|
|
|
+ SyncLockRGet(ctx, options, key, returnSize, returnValue, database, expire, password, timeout);
|
|
returnLength = static_cast<size32_t>(rtlUtf8Length(returnSize, returnValue));
|
|
returnLength = static_cast<size32_t>(rtlUtf8Length(returnSize, returnValue));
|
|
}
|
|
}
|
|
ECL_REDIS_API void ECL_REDIS_CALL SyncLockRUnlock(ICodeContext * ctx, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout)
|
|
ECL_REDIS_API void ECL_REDIS_CALL SyncLockRUnlock(ICodeContext * ctx, const char * key, const char * options, unsigned __int64 database, const char * password, unsigned __int64 timeout)
|