Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
dfeb899b
Commit
dfeb899b
authored
Apr 06, 2011
by
Pieter Noordhuis
Browse files
Merge branch '2.2' into 2.2-zset
Conflicts: src/object.c
parents
724376a0
2b886275
Changes
7
Show whitespace changes
Inline
Side-by-side
00-RELEASENOTES
View file @
dfeb899b
...
@@ -12,6 +12,21 @@ for 2.0.
...
@@ -12,6 +12,21 @@ for 2.0.
CHANGELOG
CHANGELOG
---------
---------
What's new in Redis 2.2.4
=========================
* Return value of OBJECT DEBUG against sorted sets fixed, now is "skiplist".
What's new in Redis 2.2.3
=========================
* Fixed issue #503. MONITOR + QUIT (and other combinations) could crash
the server.
* OBJECT command implemented. See http://redis.io/commands/object
* Fixed a problem in redis-cli related to escapes in the form "\x..".
* Fixed a minor memory leak in redis-cli
* Saved RDB on SIGTERM on archs where it was not working properly.
What's new in Redis 2.2.2
What's new in Redis 2.2.2
=========================
=========================
...
...
src/networking.c
View file @
dfeb899b
...
@@ -60,9 +60,6 @@ redisClient *createClient(int fd) {
...
@@ -60,9 +60,6 @@ redisClient *createClient(int fd) {
/* Set the event loop to listen for write events on the client's socket.
/* Set the event loop to listen for write events on the client's socket.
* Typically gets called every time a reply is built. */
* Typically gets called every time a reply is built. */
int
_installWriteEvent
(
redisClient
*
c
)
{
int
_installWriteEvent
(
redisClient
*
c
)
{
/* When CLOSE_AFTER_REPLY is set, no more replies may be added! */
redisAssert
(
!
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
));
if
(
c
->
fd
<=
0
)
return
REDIS_ERR
;
if
(
c
->
fd
<=
0
)
return
REDIS_ERR
;
if
(
c
->
bufpos
==
0
&&
listLength
(
c
->
reply
)
==
0
&&
if
(
c
->
bufpos
==
0
&&
listLength
(
c
->
reply
)
==
0
&&
(
c
->
replstate
==
REDIS_REPL_NONE
||
(
c
->
replstate
==
REDIS_REPL_NONE
||
...
@@ -88,9 +85,15 @@ robj *dupLastObjectIfNeeded(list *reply) {
...
@@ -88,9 +85,15 @@ robj *dupLastObjectIfNeeded(list *reply) {
return
listNodeValue
(
ln
);
return
listNodeValue
(
ln
);
}
}
/* -----------------------------------------------------------------------------
* Low level functions to add more data to output buffers.
* -------------------------------------------------------------------------- */
int
_addReplyToBuffer
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
int
_addReplyToBuffer
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
size_t
available
=
sizeof
(
c
->
buf
)
-
c
->
bufpos
;
size_t
available
=
sizeof
(
c
->
buf
)
-
c
->
bufpos
;
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
return
REDIS_OK
;
/* If there already are entries in the reply list, we cannot
/* If there already are entries in the reply list, we cannot
* add anything more to the static buffer. */
* add anything more to the static buffer. */
if
(
listLength
(
c
->
reply
)
>
0
)
return
REDIS_ERR
;
if
(
listLength
(
c
->
reply
)
>
0
)
return
REDIS_ERR
;
...
@@ -105,6 +108,9 @@ int _addReplyToBuffer(redisClient *c, char *s, size_t len) {
...
@@ -105,6 +108,9 @@ int _addReplyToBuffer(redisClient *c, char *s, size_t len) {
void
_addReplyObjectToList
(
redisClient
*
c
,
robj
*
o
)
{
void
_addReplyObjectToList
(
redisClient
*
c
,
robj
*
o
)
{
robj
*
tail
;
robj
*
tail
;
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
return
;
if
(
listLength
(
c
->
reply
)
==
0
)
{
if
(
listLength
(
c
->
reply
)
==
0
)
{
incrRefCount
(
o
);
incrRefCount
(
o
);
listAddNodeTail
(
c
->
reply
,
o
);
listAddNodeTail
(
c
->
reply
,
o
);
...
@@ -128,6 +134,12 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
...
@@ -128,6 +134,12 @@ void _addReplyObjectToList(redisClient *c, robj *o) {
* needed it will be free'd, otherwise it ends up in a robj. */
* needed it will be free'd, otherwise it ends up in a robj. */
void
_addReplySdsToList
(
redisClient
*
c
,
sds
s
)
{
void
_addReplySdsToList
(
redisClient
*
c
,
sds
s
)
{
robj
*
tail
;
robj
*
tail
;
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
{
sdsfree
(
s
);
return
;
}
if
(
listLength
(
c
->
reply
)
==
0
)
{
if
(
listLength
(
c
->
reply
)
==
0
)
{
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
}
else
{
}
else
{
...
@@ -148,6 +160,9 @@ void _addReplySdsToList(redisClient *c, sds s) {
...
@@ -148,6 +160,9 @@ void _addReplySdsToList(redisClient *c, sds s) {
void
_addReplyStringToList
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
void
_addReplyStringToList
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
robj
*
tail
;
robj
*
tail
;
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
return
;
if
(
listLength
(
c
->
reply
)
==
0
)
{
if
(
listLength
(
c
->
reply
)
==
0
)
{
listAddNodeTail
(
c
->
reply
,
createStringObject
(
s
,
len
));
listAddNodeTail
(
c
->
reply
,
createStringObject
(
s
,
len
));
}
else
{
}
else
{
...
@@ -165,6 +180,11 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
...
@@ -165,6 +180,11 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
}
}
}
}
/* -----------------------------------------------------------------------------
* Higher level functions to queue data on the client output buffer.
* The following functions are the ones that commands implementations will call.
* -------------------------------------------------------------------------- */
void
addReply
(
redisClient
*
c
,
robj
*
obj
)
{
void
addReply
(
redisClient
*
c
,
robj
*
obj
)
{
if
(
_installWriteEvent
(
c
)
!=
REDIS_OK
)
return
;
if
(
_installWriteEvent
(
c
)
!=
REDIS_OK
)
return
;
redisAssert
(
!
server
.
vm_enabled
||
obj
->
storage
==
REDIS_VM_MEMORY
);
redisAssert
(
!
server
.
vm_enabled
||
obj
->
storage
==
REDIS_VM_MEMORY
);
...
...
src/object.c
View file @
dfeb899b
...
@@ -93,9 +93,13 @@ robj *createHashObject(void) {
...
@@ -93,9 +93,13 @@ robj *createHashObject(void) {
robj
*
createZsetObject
(
void
)
{
robj
*
createZsetObject
(
void
)
{
zset
*
zs
=
zmalloc
(
sizeof
(
*
zs
));
zset
*
zs
=
zmalloc
(
sizeof
(
*
zs
));
robj
*
o
;
zs
->
dict
=
dictCreate
(
&
zsetDictType
,
NULL
);
zs
->
dict
=
dictCreate
(
&
zsetDictType
,
NULL
);
zs
->
zsl
=
zslCreate
();
zs
->
zsl
=
zslCreate
();
return
createObject
(
REDIS_ZSET
,
zs
);
o
=
createObject
(
REDIS_ZSET
,
zs
);
o
->
encoding
=
REDIS_ENCODING_SKIPLIST
;
return
o
;
}
}
robj
*
createZsetZiplistObject
(
void
)
{
robj
*
createZsetZiplistObject
(
void
)
{
...
@@ -440,6 +444,7 @@ char *strEncoding(int encoding) {
...
@@ -440,6 +444,7 @@ char *strEncoding(int encoding) {
case
REDIS_ENCODING_LINKEDLIST
:
return
"linkedlist"
;
case
REDIS_ENCODING_LINKEDLIST
:
return
"linkedlist"
;
case
REDIS_ENCODING_ZIPLIST
:
return
"ziplist"
;
case
REDIS_ENCODING_ZIPLIST
:
return
"ziplist"
;
case
REDIS_ENCODING_INTSET
:
return
"intset"
;
case
REDIS_ENCODING_INTSET
:
return
"intset"
;
case
REDIS_ENCODING_SKIPLIST
:
return
"skiplist"
;
default:
return
"unknown"
;
default:
return
"unknown"
;
}
}
}
}
...
@@ -454,3 +459,42 @@ unsigned long estimateObjectIdleTime(robj *o) {
...
@@ -454,3 +459,42 @@ unsigned long estimateObjectIdleTime(robj *o) {
REDIS_LRU_CLOCK_RESOLUTION
;
REDIS_LRU_CLOCK_RESOLUTION
;
}
}
}
}
/* This is an helper function for the DEBUG command. We need to lookup keys
* without any modification of LRU or other parameters. */
robj
*
objectCommandLookup
(
redisClient
*
c
,
robj
*
key
)
{
dictEntry
*
de
;
if
((
de
=
dictFind
(
c
->
db
->
dict
,
key
->
ptr
))
==
NULL
)
return
NULL
;
return
(
robj
*
)
dictGetEntryVal
(
de
);
}
robj
*
objectCommandLookupOrReply
(
redisClient
*
c
,
robj
*
key
,
robj
*
reply
)
{
robj
*
o
=
objectCommandLookup
(
c
,
key
);
if
(
!
o
)
addReply
(
c
,
reply
);
return
o
;
}
/* Object command allows to inspect the internals of an Redis Object.
* Usage: OBJECT <verb> ... arguments ... */
void
objectCommand
(
redisClient
*
c
)
{
robj
*
o
;
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"refcount"
)
&&
c
->
argc
==
3
)
{
if
((
o
=
objectCommandLookupOrReply
(
c
,
c
->
argv
[
2
],
shared
.
nullbulk
))
==
NULL
)
return
;
addReplyLongLong
(
c
,
o
->
refcount
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"encoding"
)
&&
c
->
argc
==
3
)
{
if
((
o
=
objectCommandLookupOrReply
(
c
,
c
->
argv
[
2
],
shared
.
nullbulk
))
==
NULL
)
return
;
addReplyBulkCString
(
c
,
strEncoding
(
o
->
encoding
));
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"idletime"
)
&&
c
->
argc
==
3
)
{
if
((
o
=
objectCommandLookupOrReply
(
c
,
c
->
argv
[
2
],
shared
.
nullbulk
))
==
NULL
)
return
;
addReplyLongLong
(
c
,
estimateObjectIdleTime
(
o
));
}
else
{
addReplyError
(
c
,
"Syntax error. Try OBJECT (refcount|encoding|idletime)"
);
}
}
src/redis.c
View file @
dfeb899b
...
@@ -187,7 +187,8 @@ struct redisCommand readonlyCommandTable[] = {
...
@@ -187,7 +187,8 @@ struct redisCommand readonlyCommandTable[] = {
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
REDIS_CMD_FORCE_REPLICATION
,
NULL
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
REDIS_CMD_FORCE_REPLICATION
,
NULL
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"unwatch"
,
unwatchCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
}
{
"unwatch"
,
unwatchCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"object"
,
objectCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
}
};
};
/*============================ Utility functions ============================ */
/*============================ Utility functions ============================ */
...
...
src/redis.h
View file @
dfeb899b
...
@@ -81,6 +81,7 @@
...
@@ -81,6 +81,7 @@
#define REDIS_ENCODING_LINKEDLIST 4
/* Encoded as regular linked list */
#define REDIS_ENCODING_LINKEDLIST 4
/* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5
/* Encoded as ziplist */
#define REDIS_ENCODING_ZIPLIST 5
/* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6
/* Encoded as intset */
#define REDIS_ENCODING_INTSET 6
/* Encoded as intset */
#define REDIS_ENCODING_SKIPLIST 7
/* Encoded as skiplist */
/* Object types only used for dumping to disk */
/* Object types only used for dumping to disk */
#define REDIS_EXPIRETIME 253
#define REDIS_EXPIRETIME 253
...
@@ -1021,6 +1022,7 @@ void punsubscribeCommand(redisClient *c);
...
@@ -1021,6 +1022,7 @@ void punsubscribeCommand(redisClient *c);
void
publishCommand
(
redisClient
*
c
);
void
publishCommand
(
redisClient
*
c
);
void
watchCommand
(
redisClient
*
c
);
void
watchCommand
(
redisClient
*
c
);
void
unwatchCommand
(
redisClient
*
c
);
void
unwatchCommand
(
redisClient
*
c
);
void
objectCommand
(
redisClient
*
c
);
#if defined(__GNUC__)
#if defined(__GNUC__)
void
*
calloc
(
size_t
count
,
size_t
size
)
__attribute__
((
deprecated
));
void
*
calloc
(
size_t
count
,
size_t
size
)
__attribute__
((
deprecated
));
...
...
src/sds.c
View file @
dfeb899b
...
@@ -26,6 +26,12 @@
...
@@ -26,6 +26,12 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* POSSIBILITY OF SUCH DAMAGE.
*
* History:
*
* - 22 March 2011: History section created on top of sds.c
* - 22 March 2011: Fixed a problem with "\xab" escapes convertion in
* function sdssplitargs().
*/
*/
#define SDS_ABORT_ON_OOM
#define SDS_ABORT_ON_OOM
...
@@ -412,6 +418,37 @@ sds sdscatrepr(sds s, char *p, size_t len) {
...
@@ -412,6 +418,37 @@ sds sdscatrepr(sds s, char *p, size_t len) {
return
sdscatlen
(
s
,
"
\"
"
,
1
);
return
sdscatlen
(
s
,
"
\"
"
,
1
);
}
}
/* Helper function for sdssplitargs() that returns non zero if 'c'
* is a valid hex digit. */
int
is_hex_digit
(
char
c
)
{
return
(
c
>=
'0'
&&
c
<=
'9'
)
||
(
c
>=
'a'
&&
c
<=
'f'
)
||
(
c
>=
'A'
&&
c
<=
'F'
);
}
/* Helper function for sdssplitargs() that converts an hex digit into an
* integer from 0 to 15 */
int
hex_digit_to_int
(
char
c
)
{
switch
(
c
)
{
case
'0'
:
return
0
;
case
'1'
:
return
1
;
case
'2'
:
return
2
;
case
'3'
:
return
3
;
case
'4'
:
return
4
;
case
'5'
:
return
5
;
case
'6'
:
return
6
;
case
'7'
:
return
7
;
case
'8'
:
return
8
;
case
'9'
:
return
9
;
case
'a'
:
case
'A'
:
return
10
;
case
'b'
:
case
'B'
:
return
11
;
case
'c'
:
case
'C'
:
return
12
;
case
'd'
:
case
'D'
:
return
13
;
case
'e'
:
case
'E'
:
return
14
;
case
'f'
:
case
'F'
:
return
15
;
default:
return
0
;
}
}
/* Split a line into arguments, where every argument can be in the
/* Split a line into arguments, where every argument can be in the
* following programming-language REPL-alike form:
* following programming-language REPL-alike form:
*
*
...
@@ -441,7 +478,17 @@ sds *sdssplitargs(char *line, int *argc) {
...
@@ -441,7 +478,17 @@ sds *sdssplitargs(char *line, int *argc) {
if
(
current
==
NULL
)
current
=
sdsempty
();
if
(
current
==
NULL
)
current
=
sdsempty
();
while
(
!
done
)
{
while
(
!
done
)
{
if
(
inq
)
{
if
(
inq
)
{
if
(
*
p
==
'\\'
&&
*
(
p
+
1
))
{
if
(
*
p
==
'\\'
&&
*
(
p
+
1
)
==
'x'
&&
is_hex_digit
(
*
(
p
+
2
))
&&
is_hex_digit
(
*
(
p
+
3
)))
{
unsigned
char
byte
;
byte
=
(
hex_digit_to_int
(
*
(
p
+
2
))
*
16
)
+
hex_digit_to_int
(
*
(
p
+
3
));
current
=
sdscatlen
(
current
,(
char
*
)
&
byte
,
1
);
p
+=
3
;
}
else
if
(
*
p
==
'\\'
&&
*
(
p
+
1
))
{
char
c
;
char
c
;
p
++
;
p
++
;
...
...
src/version.h
View file @
dfeb899b
#define REDIS_VERSION "2.2.
2
"
#define REDIS_VERSION "2.2.
4
"
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