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
9f9e1cea
Commit
9f9e1cea
authored
Dec 14, 2010
by
Pieter Noordhuis
Browse files
Add SETRANGE command implementation and tests
parent
7ecd4644
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/redis.c
View file @
9f9e1cea
...
...
@@ -80,6 +80,7 @@ struct redisCommand readonlyCommandTable[] = {
{
"exists"
,
existsCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"setbit"
,
setbitCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"getbit"
,
getbitCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"setrange"
,
setrangeCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"incr"
,
incrCommand
,
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"decr"
,
decrCommand
,
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"mget"
,
mgetCommand
,
-
2
,
0
,
NULL
,
1
,
-
1
,
1
},
...
...
src/redis.h
View file @
9f9e1cea
...
...
@@ -889,6 +889,7 @@ void delCommand(redisClient *c);
void
existsCommand
(
redisClient
*
c
);
void
setbitCommand
(
redisClient
*
c
);
void
getbitCommand
(
redisClient
*
c
);
void
setrangeCommand
(
redisClient
*
c
);
void
incrCommand
(
redisClient
*
c
);
void
decrCommand
(
redisClient
*
c
);
void
incrbyCommand
(
redisClient
*
c
);
...
...
src/t_string.c
View file @
9f9e1cea
...
...
@@ -5,6 +5,14 @@
* String Commands
*----------------------------------------------------------------------------*/
static
int
checkStringLength
(
redisClient
*
c
,
long
long
size
)
{
if
(
size
>
512
*
1024
*
1024
)
{
addReplyError
(
c
,
"string exceeds maximum allowed size (512MB)"
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
}
void
setGenericCommand
(
redisClient
*
c
,
int
nx
,
robj
*
key
,
robj
*
val
,
robj
*
expire
)
{
int
retval
;
long
seconds
=
0
;
/* initialized to avoid an harmness warning */
...
...
@@ -172,6 +180,83 @@ void getbitCommand(redisClient *c) {
addReply
(
c
,
on
?
shared
.
cone
:
shared
.
czero
);
}
void
setrangeCommand
(
redisClient
*
c
)
{
robj
*
o
;
long
offset
;
sds
value
=
c
->
argv
[
3
]
->
ptr
;
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
offset
,
NULL
)
!=
REDIS_OK
)
return
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
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 */
if
(
sdslen
(
value
)
==
0
)
{
addReply
(
c
,
shared
.
czero
);
return
;
}
/* Return when the resulting string exceeds allowed size */
if
(
checkStringLength
(
c
,
offset
+
sdslen
(
value
))
!=
REDIS_OK
)
return
;
o
=
createObject
(
REDIS_STRING
,
sdsempty
());
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
else
{
int
olen
;
/* Key exists, check type */
if
(
checkType
(
c
,
o
,
REDIS_STRING
))
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 */
if
(
sdslen
(
value
)
==
0
)
{
addReplyLongLong
(
c
,
olen
);
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 */
if
(
checkStringLength
(
c
,
offset
+
sdslen
(
value
))
!=
REDIS_OK
)
return
;
/* Create a copy when the object is shared or encoded. */
if
(
o
->
refcount
!=
1
||
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
robj
*
decoded
=
getDecodedObject
(
o
);
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
decrRefCount
(
decoded
);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
}
if
(
sdslen
(
value
)
>
0
)
{
o
->
ptr
=
sdsgrowzero
(
o
->
ptr
,
offset
+
sdslen
(
value
));
memcpy
((
char
*
)
o
->
ptr
+
offset
,
value
,
sdslen
(
value
));
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
}
addReplyLongLong
(
c
,
sdslen
(
o
->
ptr
));
}
void
mgetCommand
(
redisClient
*
c
)
{
int
j
;
...
...
tests/unit/basic.tcl
View file @
9f9e1cea
...
...
@@ -458,4 +458,108 @@ start_server {tags {"basic"}} {
assert_equal 0
[
r getbit mykey 100
]
assert_equal 0
[
r getbit mykey 10000
]
}
test
"SETRANGE against non-existing key"
{
r del mykey
assert_equal 3
[
r setrange mykey 0 foo
]
assert_equal
"foo"
[
r get mykey
]
r del mykey
assert_equal 0
[
r setrange mykey 0
""
]
assert_equal 0
[
r exists mykey
]
r del mykey
assert_equal 4
[
r setrange mykey 1 foo
]
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"
{
r set mykey
"foo"
assert_equal 3
[
r setrange mykey 0 b
]
assert_equal
"boo"
[
r get mykey
]
r set mykey
"foo"
assert_equal 3
[
r setrange mykey 0
""
]
assert_equal
"foo"
[
r get mykey
]
r set mykey
"foo"
assert_equal 3
[
r setrange mykey 1 b
]
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"
assert_equal 7
[
r setrange mykey 4 bar
]
assert_equal
"foo
\000
bar"
[
r get mykey
]
}
test
"SETRANGE against integer-encoded key"
{
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey 0 2
]
assert_encoding raw mykey
assert_equal 2234
[
r get mykey
]
# Shouldn't change encoding when nothing is set
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey 0
""
]
assert_encoding int mykey
assert_equal 1234
[
r get mykey
]
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey 1 3
]
assert_encoding raw 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
assert_encoding int mykey
assert_equal 6
[
r setrange mykey 5 2
]
assert_encoding raw mykey
assert_equal
"1234
\000
2"
[
r get mykey
]
}
test
"SETRANGE against key with wrong type"
{
r del mykey
r lpush mykey
"foo"
assert_error
"*wrong kind*"
{
r setrange mykey 0 bar
}
}
test
"SETRANGE with out of range offset"
{
r del mykey
assert_error
"*maximum allowed size*"
{
r setrange mykey
[
expr 512*1024*1024-4
]
world
}
r set mykey
"hello"
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