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
53f0efe2
Commit
53f0efe2
authored
Dec 15, 2010
by
antirez
Browse files
Merge remote branch 'pietern/string-patches'
parents
180e07b8
7d5f5712
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/t_string.c
View file @
53f0efe2
...
@@ -111,17 +111,18 @@ void setbitCommand(redisClient *c) {
...
@@ -111,17 +111,18 @@ void setbitCommand(redisClient *c) {
robj
*
o
;
robj
*
o
;
char
*
err
=
"bit is not an integer or out of range"
;
char
*
err
=
"bit is not an integer or out of range"
;
size_t
bitoffset
;
size_t
bitoffset
;
long
long
bitvalue
;
int
byte
,
bit
;
int
byte
,
bit
,
on
;
int
byteval
,
bitval
;
long
on
;
if
(
getBitOffsetFromArgument
(
c
,
c
->
argv
[
2
],
&
bitoffset
)
!=
REDIS_OK
)
if
(
getBitOffsetFromArgument
(
c
,
c
->
argv
[
2
],
&
bitoffset
)
!=
REDIS_OK
)
return
;
return
;
if
(
getLong
Long
FromObjectOrReply
(
c
,
c
->
argv
[
3
],
&
bitvalue
,
err
)
!=
REDIS_OK
)
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
3
],
&
on
,
err
)
!=
REDIS_OK
)
return
;
return
;
/*
A b
it can only be set
to be on or off
... */
/*
B
it
s
can only be set
or cleared
... */
if
(
bitvalue
&
~
1
)
{
if
(
on
&
~
1
)
{
addReplyError
(
c
,
err
);
addReplyError
(
c
,
err
);
return
;
return
;
}
}
...
@@ -142,23 +143,30 @@ void setbitCommand(redisClient *c) {
...
@@ -142,23 +143,30 @@ void setbitCommand(redisClient *c) {
}
}
}
}
/* Grow sds value to the right length if necessary */
byte
=
bitoffset
>>
3
;
byte
=
bitoffset
>>
3
;
bit
=
7
-
(
bitoffset
&
0x7
);
on
=
bitvalue
&
0x1
;
o
->
ptr
=
sdsgrowzero
(
o
->
ptr
,
byte
+
1
);
o
->
ptr
=
sdsgrowzero
(
o
->
ptr
,
byte
+
1
);
((
char
*
)
o
->
ptr
)[
byte
]
|=
on
<<
bit
;
((
char
*
)
o
->
ptr
)[
byte
]
&=
~
((
!
on
)
<<
bit
);
/* Get current values */
byteval
=
((
char
*
)
o
->
ptr
)[
byte
];
bit
=
7
-
(
bitoffset
&
0x7
);
bitval
=
byteval
&
(
1
<<
bit
);
/* Update byte with new bit value and return original value */
byteval
&=
~
(
1
<<
bit
);
byteval
|=
((
on
&
0x1
)
<<
bit
);
((
char
*
)
o
->
ptr
)[
byte
]
=
byteval
;
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
server
.
dirty
++
;
addReply
(
c
,
shared
.
cone
);
addReply
(
c
,
bitval
?
shared
.
cone
:
shared
.
czero
);
}
}
void
getbitCommand
(
redisClient
*
c
)
{
void
getbitCommand
(
redisClient
*
c
)
{
robj
*
o
;
robj
*
o
;
size_t
bitoffset
,
byte
,
bitmask
;
int
on
=
0
;
char
llbuf
[
32
];
char
llbuf
[
32
];
size_t
bitoffset
;
size_t
byte
,
bit
;
size_t
bitval
=
0
;
if
(
getBitOffsetFromArgument
(
c
,
c
->
argv
[
2
],
&
bitoffset
)
!=
REDIS_OK
)
if
(
getBitOffsetFromArgument
(
c
,
c
->
argv
[
2
],
&
bitoffset
)
!=
REDIS_OK
)
return
;
return
;
...
@@ -167,15 +175,16 @@ void getbitCommand(redisClient *c) {
...
@@ -167,15 +175,16 @@ void getbitCommand(redisClient *c) {
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
byte
=
bitoffset
>>
3
;
byte
=
bitoffset
>>
3
;
bit
mask
=
1
<<
(
7
-
(
bitoffset
&
0x7
)
)
;
bit
=
7
-
(
bitoffset
&
0x7
);
if
(
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
if
(
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
if
(
byte
<
(
size_t
)
ll2string
(
llbuf
,
sizeof
(
llbuf
),(
long
)
o
->
ptr
))
if
(
byte
<
(
size_t
)
ll2string
(
llbuf
,
sizeof
(
llbuf
),(
long
)
o
->
ptr
))
on
=
llbuf
[
byte
]
&
bitmask
;
bitval
=
llbuf
[
byte
]
&
(
1
<<
bit
)
;
}
else
{
}
else
{
if
(
byte
<
sdslen
(
o
->
ptr
))
if
(
byte
<
sdslen
(
o
->
ptr
))
on
=
((
sds
)
o
->
ptr
)[
byte
]
&
bitmask
;
bitval
=
((
char
*
)
o
->
ptr
)[
byte
]
&
(
1
<<
bit
)
;
}
}
addReply
(
c
,
on
?
shared
.
cone
:
shared
.
czero
);
addReply
(
c
,
bitval
?
shared
.
cone
:
shared
.
czero
);
}
}
void
setrangeCommand
(
redisClient
*
c
)
{
void
setrangeCommand
(
redisClient
*
c
)
{
...
@@ -186,11 +195,13 @@ void setrangeCommand(redisClient *c) {
...
@@ -186,11 +195,13 @@ void setrangeCommand(redisClient *c) {
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
offset
,
NULL
)
!=
REDIS_OK
)
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
offset
,
NULL
)
!=
REDIS_OK
)
return
;
return
;
if
(
offset
<
0
)
{
addReplyError
(
c
,
"offset is out of range"
);
return
;
}
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
if
(
o
==
NULL
)
{
if
(
o
==
NULL
)
{
/* Negative offset is always 0 for non-existing keys */
if
(
offset
<
0
)
offset
=
0
;
/* Return 0 when setting nothing on a non-existing string */
/* Return 0 when setting nothing on a non-existing string */
if
(
sdslen
(
value
)
==
0
)
{
if
(
sdslen
(
value
)
==
0
)
{
addReply
(
c
,
shared
.
czero
);
addReply
(
c
,
shared
.
czero
);
...
@@ -204,35 +215,19 @@ void setrangeCommand(redisClient *c) {
...
@@ -204,35 +215,19 @@ void setrangeCommand(redisClient *c) {
o
=
createObject
(
REDIS_STRING
,
sdsempty
());
o
=
createObject
(
REDIS_STRING
,
sdsempty
());
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
o
);
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
else
{
}
else
{
in
t
olen
;
size_
t
olen
;
/* Key exists, check type */
/* Key exists, check type */
if
(
checkType
(
c
,
o
,
REDIS_STRING
))
if
(
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
return
;
/* Find out existing value length */
if
(
o
->
encoding
==
REDIS_ENCODING_INT
)
{
char
llbuf
[
32
];
olen
=
ll2string
(
llbuf
,
sizeof
(
llbuf
),(
long
)
o
->
ptr
);
}
else
{
olen
=
sdslen
(
o
->
ptr
);
}
/* Return existing string length when setting nothing */
/* Return existing string length when setting nothing */
olen
=
stringObjectLen
(
o
);
if
(
sdslen
(
value
)
==
0
)
{
if
(
sdslen
(
value
)
==
0
)
{
addReplyLongLong
(
c
,
olen
);
addReplyLongLong
(
c
,
olen
);
return
;
return
;
}
}
/* Convert negative indexes. Note that for SETRANGE, the meaning of a
* negative index is a little different than for other commands.
* Here, an offset of -1 points to the trailing NULL byte of the
* string instead of the last character. */
if
(
offset
<
0
)
{
offset
=
olen
+
1
+
offset
;
if
(
offset
<
0
)
offset
=
0
;
}
/* Return when the resulting string exceeds allowed size */
/* Return when the resulting string exceeds allowed size */
if
(
checkStringLength
(
c
,
offset
+
sdslen
(
value
))
!=
REDIS_OK
)
if
(
checkStringLength
(
c
,
offset
+
sdslen
(
value
))
!=
REDIS_OK
)
return
;
return
;
...
@@ -391,31 +386,26 @@ void decrbyCommand(redisClient *c) {
...
@@ -391,31 +386,26 @@ void decrbyCommand(redisClient *c) {
}
}
void
appendCommand
(
redisClient
*
c
)
{
void
appendCommand
(
redisClient
*
c
)
{
int
retval
;
size_t
totlen
;
size_t
totlen
;
robj
*
o
,
*
append
;
robj
*
o
,
*
append
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
o
==
NULL
)
{
if
(
o
==
NULL
)
{
/* Create the key */
/* Create the key */
retval
=
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
incrRefCount
(
c
->
argv
[
2
]);
incrRefCount
(
c
->
argv
[
2
]);
totlen
=
stringObjectLen
(
c
->
argv
[
2
]);
totlen
=
stringObjectLen
(
c
->
argv
[
2
]);
}
else
{
}
else
{
if
(
o
->
type
!=
REDIS_STRING
)
{
/* Key exists, check type */
addReply
(
c
,
shared
.
wrongtypeerr
);
if
(
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
return
;
}
append
=
getDecodedObject
(
c
->
argv
[
2
]);
/* "append" is an argument, so always an sds */
if
(
o
->
encoding
==
REDIS_ENCODING_RAW
&&
append
=
c
->
argv
[
2
];
(
sdslen
(
o
->
ptr
)
+
sdslen
(
append
->
ptr
))
>
512
*
1024
*
1024
)
totlen
=
stringObjectLen
(
o
)
+
sdslen
(
append
->
ptr
);
{
if
(
checkStringLength
(
c
,
totlen
)
!=
REDIS_OK
)
addReplyError
(
c
,
"string exceeds maximum allowed size (512MB)"
);
decrRefCount
(
append
);
return
;
return
;
}
/* If the object is shared or encoded, we have to make a copy */
/* If the object is shared or encoded, we have to make a copy */
if
(
o
->
refcount
!=
1
||
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
if
(
o
->
refcount
!=
1
||
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
...
@@ -427,7 +417,6 @@ void appendCommand(redisClient *c) {
...
@@ -427,7 +417,6 @@ void appendCommand(redisClient *c) {
/* Append the value */
/* Append the value */
o
->
ptr
=
sdscatlen
(
o
->
ptr
,
append
->
ptr
,
sdslen
(
append
->
ptr
));
o
->
ptr
=
sdscatlen
(
o
->
ptr
,
append
->
ptr
,
sdslen
(
append
->
ptr
));
decrRefCount
(
append
);
totlen
=
sdslen
(
o
->
ptr
);
totlen
=
sdslen
(
o
->
ptr
);
}
}
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
...
@@ -437,18 +426,8 @@ void appendCommand(redisClient *c) {
...
@@ -437,18 +426,8 @@ void appendCommand(redisClient *c) {
void
strlenCommand
(
redisClient
*
c
)
{
void
strlenCommand
(
redisClient
*
c
)
{
robj
*
o
;
robj
*
o
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
addReplyLongLong
(
c
,
stringObjectLen
(
o
));
if
(
o
->
encoding
==
REDIS_ENCODING_RAW
)
{
addReplyLongLong
(
c
,
sdslen
(
o
->
ptr
));
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_INT
)
{
char
llbuf
[
32
];
int
len
=
ll2string
(
llbuf
,
sizeof
(
llbuf
),(
long
)
o
->
ptr
);
addReplyLongLong
(
c
,
len
);
}
else
{
redisPanic
(
"Unknown string encoding"
);
}
}
}
tests/unit/basic.tcl
View file @
53f0efe2
...
@@ -361,45 +361,45 @@ start_server {tags {"basic"}} {
...
@@ -361,45 +361,45 @@ start_server {tags {"basic"}} {
list
[
r msetnx x1 xxx y2 yyy
]
[
r get x1
]
[
r get y2
]
list
[
r msetnx x1 xxx y2 yyy
]
[
r get x1
]
[
r get y2
]
}
{
1 xxx yyy
}
}
{
1 xxx yyy
}
test
{
STRLEN against non
existing key
}
{
test
"
STRLEN against non
-
existing key
"
{
r strlen notakey
assert_equal 0
[
r strlen notakey
]
}
{
0
}
}
test
{
STRLEN against integer
}
{
test
"
STRLEN against integer
-encoded value"
{
r set myinteger -555
r set myinteger -555
r strlen myinteger
assert_equal 4
[
r strlen myinteger
]
}
{
4
}
}
test
{
STRLEN against plain string
}
{
test
"
STRLEN against plain string
"
{
r set mystring
"foozzz0123456789 baz"
r set mystring
"foozzz0123456789 baz"
r strlen mystring
assert_equal 20
[
r strlen mystring
]
}
}
test
"SETBIT against non-existing key"
{
test
"SETBIT against non-existing key"
{
r del mykey
r del mykey
assert_equal 0
[
r setbit mykey 1 1
]
# Setting 2nd bit to on is integer 64, ascii
"@"
assert_equal
[
binary format B* 01000000
]
[
r get mykey
]
assert_equal 1
[
r setbit mykey 1 1
]
assert_equal
"@"
[
r get mykey
]
}
}
test
"SETBIT against string-encoded key"
{
test
"SETBIT against string-encoded key"
{
#
Single byte with 2nd bit set
#
Ascii
"@"
is integer 64 = 01 00 00 00
r set mykey
"@"
r set mykey
"@"
# 64 + 32 = 96 => ascii
"`"
(
backtick
)
assert_equal 0
[
r setbit mykey 2 1
]
assert_equal 1
[
r setbit mykey 2 1
]
assert_equal
[
binary format B* 01100000
]
[
r get mykey
]
assert_equal
"`"
[
r get mykey
]
assert_equal 1
[
r setbit mykey 1 0
]
assert_equal
[
binary format B* 00100000
]
[
r get mykey
]
}
}
test
"SETBIT against integer-encoded key"
{
test
"SETBIT against integer-encoded key"
{
# Ascii
"1"
is integer 49 = 00 11 00 01
r set mykey 1
r set mykey 1
assert_encoding int mykey
assert_encoding int mykey
# Ascii
"1"
is integer 49 = 00 11 00 01
assert_equal 0
[
r setbit mykey 6 1
]
# Setting 7th bit = 51 => ascii
"3"
assert_equal
[
binary format B* 00110011
]
[
r get mykey
]
assert_equal 1
[
r setbit mykey
6 1
]
assert_equal 1
[
r setbit mykey
2 0
]
assert_equal
"3"
[
r get mykey
]
assert_equal
[
binary format B* 00010011
]
[
r get mykey
]
}
}
test
"SETBIT against key with wrong type"
{
test
"SETBIT against key with wrong type"
{
...
@@ -422,6 +422,24 @@ start_server {tags {"basic"}} {
...
@@ -422,6 +422,24 @@ start_server {tags {"basic"}} {
assert_error
"*out of range*"
{
r setbit mykey 0 20
}
assert_error
"*out of range*"
{
r setbit mykey 0 20
}
}
}
test
"SETBIT fuzzing"
{
set str
""
set len
[
expr 256*8
]
r del mykey
for
{
set i 0
}
{
$i
< 2000
}
{
incr i
}
{
set bitnum
[
randomInt $len
]
set bitval
[
randomInt 2
]
set fmt
[
format
"%%-%ds%%d%%-s"
$bitnum
]
set head
[
string range $str 0 $bitnum-1
]
set tail
[
string range $str $bitnum+1 end
]
set str
[
string map
{
" "
0
}
[
format $fmt $head $bitval $tail
]]
r setbit mykey $bitnum $bitval
assert_equal
[
binary format B* $str
]
[
r get mykey
]
}
}
test
"GETBIT against non-existing key"
{
test
"GETBIT against non-existing key"
{
r del mykey
r del mykey
assert_equal 0
[
r getbit mykey 0
]
assert_equal 0
[
r getbit mykey 0
]
...
@@ -471,14 +489,6 @@ start_server {tags {"basic"}} {
...
@@ -471,14 +489,6 @@ start_server {tags {"basic"}} {
r del mykey
r del mykey
assert_equal 4
[
r setrange mykey 1 foo
]
assert_equal 4
[
r setrange mykey 1 foo
]
assert_equal
"
\000
foo"
[
r get mykey
]
assert_equal
"
\000
foo"
[
r get mykey
]
r del mykey
assert_equal 3
[
r setrange mykey -1 foo
]
assert_equal
"foo"
[
r get mykey
]
r del mykey
assert_equal 3
[
r setrange mykey -100 foo
]
assert_equal
"foo"
[
r get mykey
]
}
}
test
"SETRANGE against string-encoded key"
{
test
"SETRANGE against string-encoded key"
{
...
@@ -494,18 +504,6 @@ start_server {tags {"basic"}} {
...
@@ -494,18 +504,6 @@ start_server {tags {"basic"}} {
assert_equal 3
[
r setrange mykey 1 b
]
assert_equal 3
[
r setrange mykey 1 b
]
assert_equal
"fbo"
[
r get mykey
]
assert_equal
"fbo"
[
r get mykey
]
r set mykey
"foo"
assert_equal 6
[
r setrange mykey -1 bar
]
assert_equal
"foobar"
[
r get mykey
]
r set mykey
"foo"
assert_equal 5
[
r setrange mykey -2 bar
]
assert_equal
"fobar"
[
r get mykey
]
r set mykey
"foo"
assert_equal 3
[
r setrange mykey -20 bar
]
assert_equal
"bar"
[
r get mykey
]
r set mykey
"foo"
r set mykey
"foo"
assert_equal 7
[
r setrange mykey 4 bar
]
assert_equal 7
[
r setrange mykey 4 bar
]
assert_equal
"foo
\000
bar"
[
r get mykey
]
assert_equal
"foo
\000
bar"
[
r get mykey
]
...
@@ -531,18 +529,6 @@ start_server {tags {"basic"}} {
...
@@ -531,18 +529,6 @@ start_server {tags {"basic"}} {
assert_encoding raw mykey
assert_encoding raw mykey
assert_equal 1334
[
r get mykey
]
assert_equal 1334
[
r get mykey
]
r set mykey 1234
assert_encoding int mykey
assert_equal 5
[
r setrange mykey -1 5
]
assert_encoding raw mykey
assert_equal 12345
[
r get mykey
]
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey -2 5
]
assert_encoding raw mykey
assert_equal 1235
[
r get mykey
]
r set mykey 1234
r set mykey 1234
assert_encoding int mykey
assert_encoding int mykey
assert_equal 6
[
r setrange mykey 5 2
]
assert_equal 6
[
r setrange mykey 5 2
]
...
@@ -559,7 +545,9 @@ start_server {tags {"basic"}} {
...
@@ -559,7 +545,9 @@ start_server {tags {"basic"}} {
test
"SETRANGE with out of range offset"
{
test
"SETRANGE with out of range offset"
{
r del mykey
r del mykey
assert_error
"*maximum allowed size*"
{
r setrange mykey
[
expr 512*1024*1024-4
]
world
}
assert_error
"*maximum allowed size*"
{
r setrange mykey
[
expr 512*1024*1024-4
]
world
}
r set mykey
"hello"
r set mykey
"hello"
assert_error
"*out of range*"
{
r setrange mykey -1 world
}
assert_error
"*maximum allowed size*"
{
r setrange mykey
[
expr 512*1024*1024-4
]
world
}
assert_error
"*maximum allowed size*"
{
r setrange mykey
[
expr 512*1024*1024-4
]
world
}
}
}
...
...
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