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
e5f1de14
Unverified
Commit
e5f1de14
authored
Oct 08, 2018
by
Salvatore Sanfilippo
Committed by
GitHub
Oct 08, 2018
Browse files
Merge pull request #5141 from soloestoy/fix-xtrim-inconsistency
Fix XTRIM and XADD with MAXLEN inconsistency
parents
8507c3f2
60acac4c
Changes
2
Show whitespace changes
Inline
Side-by-side
src/t_stream.c
View file @
e5f1de14
...
@@ -1119,8 +1119,7 @@ int streamParseStrictIDOrReply(client *c, robj *o, streamID *id, uint64_t missin
...
@@ -1119,8 +1119,7 @@ int streamParseStrictIDOrReply(client *c, robj *o, streamID *id, uint64_t missin
return
streamGenericParseIDOrReply
(
c
,
o
,
id
,
missing_seq
,
1
);
return
streamGenericParseIDOrReply
(
c
,
o
,
id
,
missing_seq
,
1
);
}
}
/* XADD key [MAXLEN [~|=] <count>] <ID or *> [field value] [field value] ... */
/* XADD key [MAXLEN <count>] <ID or *> [field value] [field value] ... */
void
xaddCommand
(
client
*
c
)
{
void
xaddCommand
(
client
*
c
)
{
streamID
id
;
streamID
id
;
int
id_given
=
0
;
/* Was an ID different than "*" specified? */
int
id_given
=
0
;
/* Was an ID different than "*" specified? */
...
@@ -1140,11 +1139,14 @@ void xaddCommand(client *c) {
...
@@ -1140,11 +1139,14 @@ void xaddCommand(client *c) {
* creation. */
* creation. */
break
;
break
;
}
else
if
(
!
strcasecmp
(
opt
,
"maxlen"
)
&&
moreargs
)
{
}
else
if
(
!
strcasecmp
(
opt
,
"maxlen"
)
&&
moreargs
)
{
approx_maxlen
=
0
;
char
*
next
=
c
->
argv
[
i
+
1
]
->
ptr
;
char
*
next
=
c
->
argv
[
i
+
1
]
->
ptr
;
/* Check for the form MAXLEN ~ <count>. */
/* Check for the form MAXLEN ~ <count>. */
if
(
moreargs
>=
2
&&
next
[
0
]
==
'~'
&&
next
[
1
]
==
'\0'
)
{
if
(
moreargs
>=
2
&&
next
[
0
]
==
'~'
&&
next
[
1
]
==
'\0'
)
{
approx_maxlen
=
1
;
approx_maxlen
=
1
;
i
++
;
i
++
;
}
else
if
(
moreargs
>=
2
&&
next
[
0
]
==
'='
&&
next
[
1
]
==
'\0'
)
{
i
++
;
}
}
if
(
getLongLongFromObjectOrReply
(
c
,
c
->
argv
[
i
+
1
],
&
maxlen
,
NULL
)
if
(
getLongLongFromObjectOrReply
(
c
,
c
->
argv
[
i
+
1
],
&
maxlen
,
NULL
)
!=
C_OK
)
return
;
!=
C_OK
)
return
;
...
@@ -1191,18 +1193,22 @@ void xaddCommand(client *c) {
...
@@ -1191,18 +1193,22 @@ void xaddCommand(client *c) {
notifyKeyspaceEvent
(
NOTIFY_STREAM
,
"xadd"
,
c
->
argv
[
1
],
c
->
db
->
id
);
notifyKeyspaceEvent
(
NOTIFY_STREAM
,
"xadd"
,
c
->
argv
[
1
],
c
->
db
->
id
);
server
.
dirty
++
;
server
.
dirty
++
;
/* Remove older elements if MAXLEN was specified. */
if
(
maxlen
>=
0
)
{
if
(
maxlen
>=
0
)
{
if
(
!
streamTrimByLength
(
s
,
maxlen
,
approx_maxlen
))
{
/* Notify xtrim event if needed. */
/* If no trimming was performed, for instance because approximated
if
(
streamTrimByLength
(
s
,
maxlen
,
approx_maxlen
))
{
* trimming length was specified, rewrite the MAXLEN argument
* as zero, so that the command is propagated without trimming. */
robj
*
zeroobj
=
createStringObjectFromLongLong
(
0
);
rewriteClientCommandArgument
(
c
,
maxlen_arg_idx
,
zeroobj
);
decrRefCount
(
zeroobj
);
}
else
{
notifyKeyspaceEvent
(
NOTIFY_STREAM
,
"xtrim"
,
c
->
argv
[
1
],
c
->
db
->
id
);
notifyKeyspaceEvent
(
NOTIFY_STREAM
,
"xtrim"
,
c
->
argv
[
1
],
c
->
db
->
id
);
}
}
/* Rewrite approximated MAXLEN as specified s->length. */
if
(
approx_maxlen
)
{
robj
*
maxlen_obj
=
createStringObjectFromLongLong
(
s
->
length
);
rewriteClientCommandArgument
(
c
,
maxlen_arg_idx
,
maxlen_obj
);
decrRefCount
(
maxlen_obj
);
robj
*
equal_obj
=
createStringObject
(
"="
,
1
);
rewriteClientCommandArgument
(
c
,
maxlen_arg_idx
-
1
,
equal_obj
);
decrRefCount
(
equal_obj
);
}
}
}
/* Let's rewrite the ID argument with the one actually generated for
/* Let's rewrite the ID argument with the one actually generated for
...
@@ -2187,7 +2193,7 @@ void xdelCommand(client *c) {
...
@@ -2187,7 +2193,7 @@ void xdelCommand(client *c) {
*
*
* List of options:
* List of options:
*
*
* MAXLEN [~] <count>
-- Trim so that the stream will be capped at
* MAXLEN [~
|=
] <count> -- Trim so that the stream will be capped at
* the specified length. Use ~ before the
* the specified length. Use ~ before the
* count in order to demand approximated trimming
* count in order to demand approximated trimming
* (like XADD MAXLEN option).
* (like XADD MAXLEN option).
...
@@ -2206,9 +2212,10 @@ void xtrimCommand(client *c) {
...
@@ -2206,9 +2212,10 @@ void xtrimCommand(client *c) {
/* Argument parsing. */
/* Argument parsing. */
int
trim_strategy
=
TRIM_STRATEGY_NONE
;
int
trim_strategy
=
TRIM_STRATEGY_NONE
;
long
long
maxlen
=
0
;
/*
0 means no maximum length
. */
long
long
maxlen
=
-
1
;
/*
If left to -1 no trimming is performed
. */
int
approx_maxlen
=
0
;
/* If 1 only delete whole radix tree nodes, so
int
approx_maxlen
=
0
;
/* If 1 only delete whole radix tree nodes, so
the maxium length is not applied verbatim. */
the maxium length is not applied verbatim. */
int
maxlen_arg_idx
=
0
;
/* Index of the count in MAXLEN, for rewriting. */
/* Parse options. */
/* Parse options. */
int
i
=
2
;
/* Start of options. */
int
i
=
2
;
/* Start of options. */
...
@@ -2216,16 +2223,25 @@ void xtrimCommand(client *c) {
...
@@ -2216,16 +2223,25 @@ void xtrimCommand(client *c) {
int
moreargs
=
(
c
->
argc
-
1
)
-
i
;
/* Number of additional arguments. */
int
moreargs
=
(
c
->
argc
-
1
)
-
i
;
/* Number of additional arguments. */
char
*
opt
=
c
->
argv
[
i
]
->
ptr
;
char
*
opt
=
c
->
argv
[
i
]
->
ptr
;
if
(
!
strcasecmp
(
opt
,
"maxlen"
)
&&
moreargs
)
{
if
(
!
strcasecmp
(
opt
,
"maxlen"
)
&&
moreargs
)
{
approx_maxlen
=
0
;
trim_strategy
=
TRIM_STRATEGY_MAXLEN
;
trim_strategy
=
TRIM_STRATEGY_MAXLEN
;
char
*
next
=
c
->
argv
[
i
+
1
]
->
ptr
;
char
*
next
=
c
->
argv
[
i
+
1
]
->
ptr
;
/* Check for the form MAXLEN ~ <count>. */
/* Check for the form MAXLEN ~ <count>. */
if
(
moreargs
>=
2
&&
next
[
0
]
==
'~'
&&
next
[
1
]
==
'\0'
)
{
if
(
moreargs
>=
2
&&
next
[
0
]
==
'~'
&&
next
[
1
]
==
'\0'
)
{
approx_maxlen
=
1
;
approx_maxlen
=
1
;
i
++
;
i
++
;
}
else
if
(
moreargs
>=
2
&&
next
[
0
]
==
'='
&&
next
[
1
]
==
'\0'
)
{
i
++
;
}
}
if
(
getLongLongFromObjectOrReply
(
c
,
c
->
argv
[
i
+
1
],
&
maxlen
,
NULL
)
if
(
getLongLongFromObjectOrReply
(
c
,
c
->
argv
[
i
+
1
],
&
maxlen
,
NULL
)
!=
C_OK
)
return
;
!=
C_OK
)
return
;
if
(
maxlen
<
0
)
{
addReplyError
(
c
,
"The MAXLEN argument must be >= 0."
);
return
;
}
i
++
;
i
++
;
maxlen_arg_idx
=
i
;
}
else
{
}
else
{
addReply
(
c
,
shared
.
syntaxerr
);
addReply
(
c
,
shared
.
syntaxerr
);
return
;
return
;
...
@@ -2246,6 +2262,17 @@ void xtrimCommand(client *c) {
...
@@ -2246,6 +2262,17 @@ void xtrimCommand(client *c) {
signalModifiedKey
(
c
->
db
,
c
->
argv
[
1
]);
signalModifiedKey
(
c
->
db
,
c
->
argv
[
1
]);
notifyKeyspaceEvent
(
NOTIFY_STREAM
,
"xtrim"
,
c
->
argv
[
1
],
c
->
db
->
id
);
notifyKeyspaceEvent
(
NOTIFY_STREAM
,
"xtrim"
,
c
->
argv
[
1
],
c
->
db
->
id
);
server
.
dirty
+=
deleted
;
server
.
dirty
+=
deleted
;
/* Rewrite approximated MAXLEN as specified s->length. */
if
(
approx_maxlen
)
{
robj
*
maxlen_obj
=
createStringObjectFromLongLong
(
s
->
length
);
rewriteClientCommandArgument
(
c
,
maxlen_arg_idx
,
maxlen_obj
);
decrRefCount
(
maxlen_obj
);
robj
*
equal_obj
=
createStringObject
(
"="
,
1
);
rewriteClientCommandArgument
(
c
,
maxlen_arg_idx
-
1
,
equal_obj
);
decrRefCount
(
equal_obj
);
}
}
}
addReplyLongLong
(
c
,
deleted
);
addReplyLongLong
(
c
,
deleted
);
}
}
...
...
tests/unit/type/stream.tcl
View file @
e5f1de14
...
@@ -317,3 +317,49 @@ start_server {
...
@@ -317,3 +317,49 @@ start_server {
assert_equal
[
r xrevrange teststream2 1234567891245 -
]
{{
1234567891240-0
{
key1 value2
}}
{
1234567891230-0
{
key1 value1
}}}
assert_equal
[
r xrevrange teststream2 1234567891245 -
]
{{
1234567891240-0
{
key1 value2
}}
{
1234567891230-0
{
key1 value1
}}}
}
}
}
}
start_server
{
tags
{
"stream"
}
overrides
{
appendonly yes
}}
{
test
{
XADD with MAXLEN > xlen can propagate correctly
}
{
for
{
set j 0
}
{
$j
< 100
}
{
incr j
}
{
r XADD mystream * xitem v
}
r XADD mystream MAXLEN 200 * xitem v
incr j
assert
{[
r xlen mystream
]
== $j
}
r debug loadaof
r XADD mystream * xitem v
incr j
assert
{[
r xlen mystream
]
== $j
}
}
}
start_server
{
tags
{
"stream"
}
overrides
{
appendonly yes
}}
{
test
{
XADD with ~ MAXLEN can propagate correctly
}
{
for
{
set j 0
}
{
$j
< 100
}
{
incr j
}
{
r XADD mystream * xitem v
}
r XADD mystream MAXLEN ~ $j * xitem v
incr j
assert
{[
r xlen mystream
]
== $j
}
r config set stream-node-max-entries 1
r debug loadaof
r XADD mystream * xitem v
incr j
assert
{[
r xlen mystream
]
== $j
}
}
}
start_server
{
tags
{
"stream"
}
overrides
{
appendonly yes stream-node-max-entries 10
}}
{
test
{
XTRIM with ~ MAXLEN can propagate correctly
}
{
for
{
set j 0
}
{
$j
< 100
}
{
incr j
}
{
r XADD mystream * xitem v
}
r XTRIM mystream MAXLEN ~ 85
assert
{[
r xlen mystream
]
== 89
}
r config set stream-node-max-entries 1
r debug loadaof
r XADD mystream * xitem v
incr j
assert
{[
r xlen mystream
]
== 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