Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
9d1baa07
Unverified
Commit
9d1baa07
authored
Dec 18, 2019
by
Salvatore Sanfilippo
Committed by
GitHub
Dec 18, 2019
Browse files
Merge pull request #6679 from soloestoy/keepttl
Add a new SET option KEEPTTL and fix issue #5256
parents
b7c78b76
58554396
Changes
9
Hide whitespace changes
Inline
Side-by-side
src/bitops.c
View file @
9d1baa07
...
@@ -754,7 +754,7 @@ void bitopCommand(client *c) {
...
@@ -754,7 +754,7 @@ void bitopCommand(client *c) {
/* Store the computed value into the target key */
/* Store the computed value into the target key */
if
(
maxlen
)
{
if
(
maxlen
)
{
o
=
createObject
(
OBJ_STRING
,
res
);
o
=
createObject
(
OBJ_STRING
,
res
);
setKey
(
c
->
db
,
targetkey
,
o
);
setKey
(
c
->
db
,
targetkey
,
o
,
0
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
targetkey
,
c
->
db
->
id
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
targetkey
,
c
->
db
->
id
);
decrRefCount
(
o
);
decrRefCount
(
o
);
}
else
if
(
dbDelete
(
c
->
db
,
targetkey
))
{
}
else
if
(
dbDelete
(
c
->
db
,
targetkey
))
{
...
...
src/db.c
View file @
9d1baa07
...
@@ -219,14 +219,14 @@ void dbOverwrite(redisDb *db, robj *key, robj *val) {
...
@@ -219,14 +219,14 @@ void dbOverwrite(redisDb *db, robj *key, robj *val) {
* 3) The expire time of the key is reset (the key is made persistent).
* 3) The expire time of the key is reset (the key is made persistent).
*
*
* All the new keys in the database should be created via this interface. */
* All the new keys in the database should be created via this interface. */
void
setKey
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
)
{
void
setKey
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
,
int
keepttl
)
{
if
(
lookupKeyWrite
(
db
,
key
)
==
NULL
)
{
if
(
lookupKeyWrite
(
db
,
key
)
==
NULL
)
{
dbAdd
(
db
,
key
,
val
);
dbAdd
(
db
,
key
,
val
);
}
else
{
}
else
{
dbOverwrite
(
db
,
key
,
val
);
dbOverwrite
(
db
,
key
,
val
);
}
}
incrRefCount
(
val
);
incrRefCount
(
val
);
removeExpire
(
db
,
key
);
if
(
!
keepttl
)
removeExpire
(
db
,
key
);
signalModifiedKey
(
db
,
key
);
signalModifiedKey
(
db
,
key
);
}
}
...
...
src/geo.c
View file @
9d1baa07
...
@@ -657,7 +657,7 @@ void georadiusGeneric(client *c, int flags) {
...
@@ -657,7 +657,7 @@ void georadiusGeneric(client *c, int flags) {
if
(
returned_items
)
{
if
(
returned_items
)
{
zsetConvertToZiplistIfNeeded
(
zobj
,
maxelelen
);
zsetConvertToZiplistIfNeeded
(
zobj
,
maxelelen
);
setKey
(
c
->
db
,
storekey
,
zobj
);
setKey
(
c
->
db
,
storekey
,
zobj
,
0
);
decrRefCount
(
zobj
);
decrRefCount
(
zobj
);
notifyKeyspaceEvent
(
NOTIFY_ZSET
,
"georadiusstore"
,
storekey
,
notifyKeyspaceEvent
(
NOTIFY_ZSET
,
"georadiusstore"
,
storekey
,
c
->
db
->
id
);
c
->
db
->
id
);
...
...
src/module.c
View file @
9d1baa07
...
@@ -2107,7 +2107,7 @@ RedisModuleString *RM_RandomKey(RedisModuleCtx *ctx) {
...
@@ -2107,7 +2107,7 @@ RedisModuleString *RM_RandomKey(RedisModuleCtx *ctx) {
int
RM_StringSet
(
RedisModuleKey
*
key
,
RedisModuleString
*
str
)
{
int
RM_StringSet
(
RedisModuleKey
*
key
,
RedisModuleString
*
str
)
{
if
(
!
(
key
->
mode
&
REDISMODULE_WRITE
)
||
key
->
iter
)
return
REDISMODULE_ERR
;
if
(
!
(
key
->
mode
&
REDISMODULE_WRITE
)
||
key
->
iter
)
return
REDISMODULE_ERR
;
RM_DeleteKey
(
key
);
RM_DeleteKey
(
key
);
setKey
(
key
->
db
,
key
->
key
,
str
);
setKey
(
key
->
db
,
key
->
key
,
str
,
0
);
key
->
value
=
str
;
key
->
value
=
str
;
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
}
}
...
@@ -2187,7 +2187,7 @@ int RM_StringTruncate(RedisModuleKey *key, size_t newlen) {
...
@@ -2187,7 +2187,7 @@ int RM_StringTruncate(RedisModuleKey *key, size_t newlen) {
if
(
key
->
value
==
NULL
)
{
if
(
key
->
value
==
NULL
)
{
/* Empty key: create it with the new size. */
/* Empty key: create it with the new size. */
robj
*
o
=
createObject
(
OBJ_STRING
,
sdsnewlen
(
NULL
,
newlen
));
robj
*
o
=
createObject
(
OBJ_STRING
,
sdsnewlen
(
NULL
,
newlen
));
setKey
(
key
->
db
,
key
->
key
,
o
);
setKey
(
key
->
db
,
key
->
key
,
o
,
0
);
key
->
value
=
o
;
key
->
value
=
o
;
decrRefCount
(
o
);
decrRefCount
(
o
);
}
else
{
}
else
{
...
@@ -3571,7 +3571,7 @@ int RM_ModuleTypeSetValue(RedisModuleKey *key, moduleType *mt, void *value) {
...
@@ -3571,7 +3571,7 @@ int RM_ModuleTypeSetValue(RedisModuleKey *key, moduleType *mt, void *value) {
if
(
!
(
key
->
mode
&
REDISMODULE_WRITE
)
||
key
->
iter
)
return
REDISMODULE_ERR
;
if
(
!
(
key
->
mode
&
REDISMODULE_WRITE
)
||
key
->
iter
)
return
REDISMODULE_ERR
;
RM_DeleteKey
(
key
);
RM_DeleteKey
(
key
);
robj
*
o
=
createModuleObject
(
mt
,
value
);
robj
*
o
=
createModuleObject
(
mt
,
value
);
setKey
(
key
->
db
,
key
->
key
,
o
);
setKey
(
key
->
db
,
key
->
key
,
o
,
0
);
decrRefCount
(
o
);
decrRefCount
(
o
);
key
->
value
=
o
;
key
->
value
=
o
;
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
...
...
src/server.h
View file @
9d1baa07
...
@@ -2025,7 +2025,7 @@ int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
...
@@ -2025,7 +2025,7 @@ int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle,
#define LOOKUP_NOTOUCH (1<<0)
#define LOOKUP_NOTOUCH (1<<0)
void
dbAdd
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
);
void
dbAdd
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
);
void
dbOverwrite
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
);
void
dbOverwrite
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
);
void
setKey
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
);
void
setKey
(
redisDb
*
db
,
robj
*
key
,
robj
*
val
,
int
keepttl
);
int
dbExists
(
redisDb
*
db
,
robj
*
key
);
int
dbExists
(
redisDb
*
db
,
robj
*
key
);
robj
*
dbRandomKey
(
redisDb
*
db
);
robj
*
dbRandomKey
(
redisDb
*
db
);
int
dbSyncDelete
(
redisDb
*
db
,
robj
*
key
);
int
dbSyncDelete
(
redisDb
*
db
,
robj
*
key
);
...
...
src/sort.c
View file @
9d1baa07
...
@@ -570,7 +570,7 @@ void sortCommand(client *c) {
...
@@ -570,7 +570,7 @@ void sortCommand(client *c) {
}
}
}
}
if
(
outputlen
)
{
if
(
outputlen
)
{
setKey
(
c
->
db
,
storekey
,
sobj
);
setKey
(
c
->
db
,
storekey
,
sobj
,
0
);
notifyKeyspaceEvent
(
NOTIFY_LIST
,
"sortstore"
,
storekey
,
notifyKeyspaceEvent
(
NOTIFY_LIST
,
"sortstore"
,
storekey
,
c
->
db
->
id
);
c
->
db
->
id
);
server
.
dirty
+=
outputlen
;
server
.
dirty
+=
outputlen
;
...
...
src/t_string.c
View file @
9d1baa07
...
@@ -46,7 +46,7 @@ static int checkStringLength(client *c, long long size) {
...
@@ -46,7 +46,7 @@ static int checkStringLength(client *c, long long size) {
* options and variants. This function is called in order to implement the
* options and variants. This function is called in order to implement the
* following commands: SET, SETEX, PSETEX, SETNX.
* following commands: SET, SETEX, PSETEX, SETNX.
*
*
* 'flags' changes the behavior of the command (NX or XX, see belo
ve
).
* 'flags' changes the behavior of the command (NX or XX, see belo
w
).
*
*
* 'expire' represents an expire to set in form of a Redis object as passed
* 'expire' represents an expire to set in form of a Redis object as passed
* by the user. It is interpreted according to the specified 'unit'.
* by the user. It is interpreted according to the specified 'unit'.
...
@@ -59,10 +59,11 @@ static int checkStringLength(client *c, long long size) {
...
@@ -59,10 +59,11 @@ static int checkStringLength(client *c, long long size) {
* If abort_reply is NULL, "$-1" is used. */
* If abort_reply is NULL, "$-1" is used. */
#define OBJ_SET_NO_FLAGS 0
#define OBJ_SET_NO_FLAGS 0
#define OBJ_SET_NX (1<<0)
/* Set if key not exists. */
#define OBJ_SET_NX (1<<0)
/* Set if key not exists. */
#define OBJ_SET_XX (1<<1)
/* Set if key exists. */
#define OBJ_SET_XX (1<<1)
/* Set if key exists. */
#define OBJ_SET_EX (1<<2)
/* Set if time in seconds is given */
#define OBJ_SET_EX (1<<2)
/* Set if time in seconds is given */
#define OBJ_SET_PX (1<<3)
/* Set if time in ms in given */
#define OBJ_SET_PX (1<<3)
/* Set if time in ms in given */
#define OBJ_SET_KEEPTTL (1<<4)
/* Set and keep the ttl */
void
setGenericCommand
(
client
*
c
,
int
flags
,
robj
*
key
,
robj
*
val
,
robj
*
expire
,
int
unit
,
robj
*
ok_reply
,
robj
*
abort_reply
)
{
void
setGenericCommand
(
client
*
c
,
int
flags
,
robj
*
key
,
robj
*
val
,
robj
*
expire
,
int
unit
,
robj
*
ok_reply
,
robj
*
abort_reply
)
{
long
long
milliseconds
=
0
;
/* initialized to avoid any harmness warning */
long
long
milliseconds
=
0
;
/* initialized to avoid any harmness warning */
...
@@ -83,7 +84,7 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire,
...
@@ -83,7 +84,7 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire,
addReply
(
c
,
abort_reply
?
abort_reply
:
shared
.
null
[
c
->
resp
]);
addReply
(
c
,
abort_reply
?
abort_reply
:
shared
.
null
[
c
->
resp
]);
return
;
return
;
}
}
setKey
(
c
->
db
,
key
,
val
);
setKey
(
c
->
db
,
key
,
val
,
flags
&
OBJ_SET_KEEPTTL
);
server
.
dirty
++
;
server
.
dirty
++
;
if
(
expire
)
setExpire
(
c
,
c
->
db
,
key
,
mstime
()
+
milliseconds
);
if
(
expire
)
setExpire
(
c
,
c
->
db
,
key
,
mstime
()
+
milliseconds
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
key
,
c
->
db
->
id
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
key
,
c
->
db
->
id
);
...
@@ -92,7 +93,7 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire,
...
@@ -92,7 +93,7 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire,
addReply
(
c
,
ok_reply
?
ok_reply
:
shared
.
ok
);
addReply
(
c
,
ok_reply
?
ok_reply
:
shared
.
ok
);
}
}
/* SET key value [NX] [XX] [EX <seconds>] [PX <milliseconds>] */
/* SET key value [NX] [XX]
[KEEPTTL]
[EX <seconds>] [PX <milliseconds>] */
void
setCommand
(
client
*
c
)
{
void
setCommand
(
client
*
c
)
{
int
j
;
int
j
;
robj
*
expire
=
NULL
;
robj
*
expire
=
NULL
;
...
@@ -113,8 +114,13 @@ void setCommand(client *c) {
...
@@ -113,8 +114,13 @@ void setCommand(client *c) {
!
(
flags
&
OBJ_SET_NX
))
!
(
flags
&
OBJ_SET_NX
))
{
{
flags
|=
OBJ_SET_XX
;
flags
|=
OBJ_SET_XX
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
j
]
->
ptr
,
"KEEPTTL"
)
&&
!
(
flags
&
OBJ_SET_EX
)
&&
!
(
flags
&
OBJ_SET_PX
))
{
flags
|=
OBJ_SET_KEEPTTL
;
}
else
if
((
a
[
0
]
==
'e'
||
a
[
0
]
==
'E'
)
&&
}
else
if
((
a
[
0
]
==
'e'
||
a
[
0
]
==
'E'
)
&&
(
a
[
1
]
==
'x'
||
a
[
1
]
==
'X'
)
&&
a
[
2
]
==
'\0'
&&
(
a
[
1
]
==
'x'
||
a
[
1
]
==
'X'
)
&&
a
[
2
]
==
'\0'
&&
!
(
flags
&
OBJ_SET_KEEPTTL
)
&&
!
(
flags
&
OBJ_SET_PX
)
&&
next
)
!
(
flags
&
OBJ_SET_PX
)
&&
next
)
{
{
flags
|=
OBJ_SET_EX
;
flags
|=
OBJ_SET_EX
;
...
@@ -123,6 +129,7 @@ void setCommand(client *c) {
...
@@ -123,6 +129,7 @@ void setCommand(client *c) {
j
++
;
j
++
;
}
else
if
((
a
[
0
]
==
'p'
||
a
[
0
]
==
'P'
)
&&
}
else
if
((
a
[
0
]
==
'p'
||
a
[
0
]
==
'P'
)
&&
(
a
[
1
]
==
'x'
||
a
[
1
]
==
'X'
)
&&
a
[
2
]
==
'\0'
&&
(
a
[
1
]
==
'x'
||
a
[
1
]
==
'X'
)
&&
a
[
2
]
==
'\0'
&&
!
(
flags
&
OBJ_SET_KEEPTTL
)
&&
!
(
flags
&
OBJ_SET_EX
)
&&
next
)
!
(
flags
&
OBJ_SET_EX
)
&&
next
)
{
{
flags
|=
OBJ_SET_PX
;
flags
|=
OBJ_SET_PX
;
...
@@ -176,7 +183,7 @@ void getCommand(client *c) {
...
@@ -176,7 +183,7 @@ void getCommand(client *c) {
void
getsetCommand
(
client
*
c
)
{
void
getsetCommand
(
client
*
c
)
{
if
(
getGenericCommand
(
c
)
==
C_ERR
)
return
;
if
(
getGenericCommand
(
c
)
==
C_ERR
)
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
setKey
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
setKey
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]
,
0
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
c
->
argv
[
1
],
c
->
db
->
id
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
c
->
argv
[
1
],
c
->
db
->
id
);
server
.
dirty
++
;
server
.
dirty
++
;
}
}
...
@@ -321,7 +328,7 @@ void msetGenericCommand(client *c, int nx) {
...
@@ -321,7 +328,7 @@ void msetGenericCommand(client *c, int nx) {
for
(
j
=
1
;
j
<
c
->
argc
;
j
+=
2
)
{
for
(
j
=
1
;
j
<
c
->
argc
;
j
+=
2
)
{
c
->
argv
[
j
+
1
]
=
tryObjectEncoding
(
c
->
argv
[
j
+
1
]);
c
->
argv
[
j
+
1
]
=
tryObjectEncoding
(
c
->
argv
[
j
+
1
]);
setKey
(
c
->
db
,
c
->
argv
[
j
],
c
->
argv
[
j
+
1
]);
setKey
(
c
->
db
,
c
->
argv
[
j
],
c
->
argv
[
j
+
1
]
,
0
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
c
->
argv
[
j
],
c
->
db
->
id
);
notifyKeyspaceEvent
(
NOTIFY_STRING
,
"set"
,
c
->
argv
[
j
],
c
->
db
->
id
);
}
}
server
.
dirty
+=
(
c
->
argc
-
1
)
/
2
;
server
.
dirty
+=
(
c
->
argc
-
1
)
/
2
;
...
@@ -398,7 +405,7 @@ void decrbyCommand(client *c) {
...
@@ -398,7 +405,7 @@ void decrbyCommand(client *c) {
void
incrbyfloatCommand
(
client
*
c
)
{
void
incrbyfloatCommand
(
client
*
c
)
{
long
double
incr
,
value
;
long
double
incr
,
value
;
robj
*
o
,
*
new
,
*
aux
;
robj
*
o
,
*
new
,
*
aux
1
,
*
aux2
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
if
(
o
!=
NULL
&&
checkType
(
c
,
o
,
OBJ_STRING
))
return
;
if
(
o
!=
NULL
&&
checkType
(
c
,
o
,
OBJ_STRING
))
return
;
...
@@ -424,10 +431,13 @@ void incrbyfloatCommand(client *c) {
...
@@ -424,10 +431,13 @@ void incrbyfloatCommand(client *c) {
/* Always replicate INCRBYFLOAT as a SET command with the final value
/* Always replicate INCRBYFLOAT as a SET command with the final value
* in order to make sure that differences in float precision or formatting
* in order to make sure that differences in float precision or formatting
* will not create differences in replicas or after an AOF restart. */
* will not create differences in replicas or after an AOF restart. */
aux
=
createStringObject
(
"SET"
,
3
);
aux
1
=
createStringObject
(
"SET"
,
3
);
rewriteClientCommandArgument
(
c
,
0
,
aux
);
rewriteClientCommandArgument
(
c
,
0
,
aux
1
);
decrRefCount
(
aux
);
decrRefCount
(
aux
1
);
rewriteClientCommandArgument
(
c
,
2
,
new
);
rewriteClientCommandArgument
(
c
,
2
,
new
);
aux2
=
createStringObject
(
"KEEPTTL"
,
7
);
rewriteClientCommandArgument
(
c
,
3
,
aux2
);
decrRefCount
(
aux2
);
}
}
void
appendCommand
(
client
*
c
)
{
void
appendCommand
(
client
*
c
)
{
...
...
tests/integration/replication.tcl
View file @
9d1baa07
...
@@ -70,6 +70,13 @@ start_server {tags {"repl"}} {
...
@@ -70,6 +70,13 @@ start_server {tags {"repl"}} {
}
}
}
}
test
{
INCRBYFLOAT replication, should not remove expire
}
{
r set test 1 EX 100
r incrbyfloat test 0.1
after 1000
assert_equal
[
$A debug digest
]
[
$B debug digest
]
}
test
{
BRPOPLPUSH replication, when blocking against empty list
}
{
test
{
BRPOPLPUSH replication, when blocking against empty list
}
{
set rd
[
redis_deferring_client
]
set rd
[
redis_deferring_client
]
$rd brpoplpush a b 5
$rd brpoplpush a b 5
...
...
tests/unit/expire.tcl
View file @
9d1baa07
...
@@ -219,4 +219,17 @@ start_server {tags {"expire"}} {
...
@@ -219,4 +219,17 @@ start_server {tags {"expire"}} {
set ttl
[
r ttl foo
]
set ttl
[
r ttl foo
]
assert
{
$ttl
<= 98 && $ttl > 90
}
assert
{
$ttl
<= 98 && $ttl > 90
}
}
}
test
{
SET command will remove expire
}
{
r set foo bar EX 100
r set foo bar
r ttl foo
}
{
-1
}
test
{
SET - use KEEPTTL option, TTL should not be removed
}
{
r set foo bar EX 100
r set foo bar KEEPTTL
set ttl
[
r ttl foo
]
assert
{
$ttl
<= 100 && $ttl > 90
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment