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
36c19d03
Commit
36c19d03
authored
Sep 02, 2010
by
Pieter Noordhuis
Browse files
Changed reply buildup internals
parent
4a7893ca
Changes
3
Show whitespace changes
Inline
Side-by-side
src/networking.c
View file @
36c19d03
...
@@ -13,13 +13,9 @@ int listMatchObjects(void *a, void *b) {
...
@@ -13,13 +13,9 @@ int listMatchObjects(void *a, void *b) {
redisClient
*
createClient
(
int
fd
)
{
redisClient
*
createClient
(
int
fd
)
{
redisClient
*
c
;
redisClient
*
c
;
/* Make sure to allocate a multiple of the page size to prevent wasting
/* Allocate more space to hold a static write buffer. */
* memory. A page size of 4096 is assumed here. We need to compensate
c
=
zmalloc
(
sizeof
(
redisClient
)
+
REDIS_REPLY_CHUNK_BYTES
);
* for the zmalloc overhead of sizeof(size_t) bytes. */
c
->
buflen
=
REDIS_REPLY_CHUNK_BYTES
;
size_t
size
=
8192
-
sizeof
(
size_t
);
redisAssert
(
size
>
sizeof
(
redisClient
));
c
=
zmalloc
(
size
);
c
->
buflen
=
size
-
sizeof
(
redisClient
);
c
->
bufpos
=
0
;
c
->
bufpos
=
0
;
anetNonBlock
(
NULL
,
fd
);
anetNonBlock
(
NULL
,
fd
);
...
@@ -71,40 +67,95 @@ int _ensureFileEvent(redisClient *c) {
...
@@ -71,40 +67,95 @@ int _ensureFileEvent(redisClient *c) {
return
REDIS_OK
;
return
REDIS_OK
;
}
}
void
_addReplyObjectToList
(
redisClient
*
c
,
robj
*
obj
)
{
/* Create a duplicate of the last object in the reply list when
redisAssert
(
obj
->
type
==
REDIS_STRING
&&
* it is not exclusively owned by the reply list. */
obj
->
encoding
==
REDIS_ENCODING_RAW
);
robj
*
dupLastObjectIfNeeded
(
list
*
reply
)
{
listAddNodeTail
(
c
->
reply
,
obj
);
robj
*
new
,
*
cur
;
listNode
*
ln
;
redisAssert
(
listLength
(
reply
)
>
0
);
ln
=
listLast
(
reply
);
cur
=
listNodeValue
(
ln
);
if
(
cur
->
refcount
>
1
)
{
new
=
dupStringObject
(
cur
);
decrRefCount
(
cur
);
listNodeValue
(
ln
)
=
new
;
}
return
listNodeValue
(
ln
);
}
}
void
_ensureBufferInReplyList
(
redisClient
*
c
)
{
int
_addReplyToBuffer
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
sds
buffer
=
sdsnewlen
(
NULL
,
REDIS_REPLY_CHUNK_SIZE
);
size_t
available
=
c
->
buflen
-
c
->
bufpos
;
sdsupdatelen
(
buffer
);
/* sdsnewlen expects non-empty string */
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_REPLY_NODE
,
buffer
));
/* If there already are entries in the reply list, we cannot
* add anything more to the static buffer. */
if
(
listLength
(
c
->
reply
)
>
0
)
return
REDIS_ERR
;
/* Check that the buffer has enough space available for this string. */
if
(
len
>
available
)
return
REDIS_ERR
;
memcpy
(
c
->
buf
+
c
->
bufpos
,
s
,
len
);
c
->
bufpos
+=
len
;
return
REDIS_OK
;
}
}
void
_addReplyStringToBuffer
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
void
_addReplyObjectToList
(
redisClient
*
c
,
robj
*
o
)
{
size_t
available
=
0
;
robj
*
tail
;
redisAssert
(
len
<
REDIS_REPLY_CHUNK_THRESHOLD
);
if
(
listLength
(
c
->
reply
)
==
0
)
{
if
(
listLength
(
c
->
reply
)
>
0
)
{
incrRefCount
(
o
);
robj
*
o
=
listNodeValue
(
listLast
(
c
->
reply
));
listAddNodeTail
(
c
->
reply
,
o
);
}
else
{
/* Make sure to append to a reply node with enough bytes available. */
tail
=
listNodeValue
(
listLast
(
c
->
reply
));
if
(
o
->
type
==
REDIS_REPLY_NODE
)
available
=
sdsavail
(
o
->
ptr
);
if
(
o
->
type
!=
REDIS_REPLY_NODE
||
len
>
available
)
{
/* Append to this object when possible. */
_ensureBufferInReplyList
(
c
);
if
(
tail
->
ptr
!=
NULL
&&
_addReplyStringToBuffer
(
c
,
s
,
len
);
sdslen
(
tail
->
ptr
)
+
sdslen
(
o
->
ptr
)
<=
REDIS_REPLY_CHUNK_BYTES
)
{
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
o
->
ptr
,
sdslen
(
o
->
ptr
));
}
else
{
}
else
{
o
->
ptr
=
sdscatlen
(
o
->
ptr
,
s
,
len
);
incrRefCount
(
o
);
listAddNodeTail
(
c
->
reply
,
o
);
}
}
}
}
/* This method takes responsibility over the sds. When it is no longer
* needed it will be free'd, otherwise it ends up in a robj. */
void
_addReplySdsToList
(
redisClient
*
c
,
sds
s
)
{
robj
*
tail
;
if
(
listLength
(
c
->
reply
)
==
0
)
{
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
}
else
{
}
else
{
available
=
c
->
buflen
-
c
->
bufpos
;
tail
=
listNodeValue
(
listLast
(
c
->
reply
));
if
(
len
>
available
)
{
_ensureBufferInReplyList
(
c
);
/* Append to this object when possible. */
_addReplyStringToBuffer
(
c
,
s
,
len
);
if
(
tail
->
ptr
!=
NULL
&&
sdslen
(
tail
->
ptr
)
+
sdslen
(
s
)
<=
REDIS_REPLY_CHUNK_BYTES
)
{
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
s
,
sdslen
(
s
));
sdsfree
(
s
);
}
else
{
}
else
{
memcpy
(
c
->
buf
+
c
->
bufpos
,
s
,
len
);
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
c
->
bufpos
+=
len
;
}
}
}
void
_addReplyStringToList
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
robj
*
tail
;
if
(
listLength
(
c
->
reply
)
==
0
)
{
listAddNodeTail
(
c
->
reply
,
createStringObject
(
s
,
len
));
}
else
{
tail
=
listNodeValue
(
listLast
(
c
->
reply
));
/* Append to this object when possible. */
if
(
tail
->
ptr
!=
NULL
&&
sdslen
(
tail
->
ptr
)
+
len
<=
REDIS_REPLY_CHUNK_BYTES
)
{
tail
=
dupLastObjectIfNeeded
(
c
->
reply
);
tail
->
ptr
=
sdscatlen
(
tail
->
ptr
,
s
,
len
);
}
else
{
listAddNodeTail
(
c
->
reply
,
createStringObject
(
s
,
len
));
}
}
}
}
}
}
...
@@ -118,13 +169,9 @@ void addReply(redisClient *c, robj *obj) {
...
@@ -118,13 +169,9 @@ void addReply(redisClient *c, robj *obj) {
/* This increments the refcount. */
/* This increments the refcount. */
obj
=
getDecodedObject
(
obj
);
obj
=
getDecodedObject
(
obj
);
}
}
if
(
_addReplyToBuffer
(
c
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
))
!=
REDIS_OK
)
if
(
sdslen
(
obj
->
ptr
)
<
REDIS_REPLY_CHUNK_THRESHOLD
)
{
_addReplyStringToBuffer
(
c
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
));
decrRefCount
(
obj
);
}
else
{
_addReplyObjectToList
(
c
,
obj
);
_addReplyObjectToList
(
c
,
obj
);
}
decrRefCount
(
obj
);
}
}
void
addReplySds
(
redisClient
*
c
,
sds
s
)
{
void
addReplySds
(
redisClient
*
c
,
sds
s
)
{
...
@@ -133,28 +180,25 @@ void addReplySds(redisClient *c, sds s) {
...
@@ -133,28 +180,25 @@ void addReplySds(redisClient *c, sds s) {
sdsfree
(
s
);
sdsfree
(
s
);
return
;
return
;
}
}
if
(
sdslen
(
s
)
<
REDIS_REPLY_CHUNK_THRESHOLD
)
{
if
(
_addReplyToBuffer
(
c
,
s
,
sdslen
(
s
))
==
REDIS_OK
)
{
_addReplyStringToBuffer
(
c
,
s
,
sdslen
(
s
));
sdsfree
(
s
);
sdsfree
(
s
);
}
else
{
}
else
{
_addReplyObjectToList
(
c
,
createObject
(
REDIS_STRING
,
s
));
/* This method free's the sds when it is no longer needed. */
_addReplySdsToList
(
c
,
s
);
}
}
}
}
void
addReplyString
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
void
addReplyString
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
if
(
_ensureFileEvent
(
c
)
!=
REDIS_OK
)
return
;
if
(
_ensureFileEvent
(
c
)
!=
REDIS_OK
)
return
;
if
(
len
<
REDIS_REPLY_CHUNK_THRESHOLD
)
{
if
(
_addReplyToBuffer
(
c
,
s
,
len
)
!=
REDIS_OK
)
_addReplyStringToBuffer
(
c
,
s
,
len
);
_addReplyStringToList
(
c
,
s
,
len
);
}
else
{
_addReplyObjectToList
(
c
,
createStringObject
(
s
,
len
));
}
}
}
/* Adds an empty object to the reply list that will contain the multi bulk
/* Adds an empty object to the reply list that will contain the multi bulk
* length, which is not known when this function is called. */
* length, which is not known when this function is called. */
void
*
addDeferredMultiBulkLength
(
redisClient
*
c
)
{
void
*
addDeferredMultiBulkLength
(
redisClient
*
c
)
{
if
(
_ensureFileEvent
(
c
)
!=
REDIS_OK
)
return
NULL
;
if
(
_ensureFileEvent
(
c
)
!=
REDIS_OK
)
return
NULL
;
_addReplyObjectToList
(
c
,
createObject
(
REDIS_STRING
,
NULL
));
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
NULL
));
return
listLast
(
c
->
reply
);
return
listLast
(
c
->
reply
);
}
}
...
@@ -170,9 +214,10 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
...
@@ -170,9 +214,10 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
len
->
ptr
=
sdscatprintf
(
sdsempty
(),
"*%ld
\r\n
"
,
length
);
len
->
ptr
=
sdscatprintf
(
sdsempty
(),
"*%ld
\r\n
"
,
length
);
if
(
ln
->
next
!=
NULL
)
{
if
(
ln
->
next
!=
NULL
)
{
next
=
listNodeValue
(
ln
->
next
);
next
=
listNodeValue
(
ln
->
next
);
/* Only glue when the next node is a reply chunk. */
if
(
next
->
type
==
REDIS_REPLY_NODE
)
{
/* Only glue when the next node is an sds */
len
->
ptr
=
sdscatlen
(
len
->
ptr
,
next
->
ptr
,
sdslen
(
next
->
ptr
));
if
(
next
->
ptr
!=
NULL
)
{
len
->
ptr
=
sdscat
(
len
->
ptr
,
next
->
ptr
);
listDelNode
(
c
->
reply
,
ln
->
next
);
listDelNode
(
c
->
reply
,
ln
->
next
);
}
}
}
}
...
...
src/object.c
View file @
36c19d03
...
@@ -196,7 +196,6 @@ void decrRefCount(void *obj) {
...
@@ -196,7 +196,6 @@ void decrRefCount(void *obj) {
case
REDIS_SET
:
freeSetObject
(
o
);
break
;
case
REDIS_SET
:
freeSetObject
(
o
);
break
;
case
REDIS_ZSET
:
freeZsetObject
(
o
);
break
;
case
REDIS_ZSET
:
freeZsetObject
(
o
);
break
;
case
REDIS_HASH
:
freeHashObject
(
o
);
break
;
case
REDIS_HASH
:
freeHashObject
(
o
);
break
;
case
REDIS_REPLY_NODE
:
freeStringObject
(
o
);
break
;
default:
redisPanic
(
"Unknown object type"
);
break
;
default:
redisPanic
(
"Unknown object type"
);
break
;
}
}
o
->
ptr
=
NULL
;
/* defensive programming. We'll see NULL in traces. */
o
->
ptr
=
NULL
;
/* defensive programming. We'll see NULL in traces. */
...
...
src/redis.h
View file @
36c19d03
...
@@ -47,15 +47,7 @@
...
@@ -47,15 +47,7 @@
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
#define REDIS_SHARED_INTEGERS 10000
#define REDIS_SHARED_INTEGERS 10000
#define REDIS_REPLY_CHUNK_BYTES (5*1500)
/* 5 TCP packets with default MTU */
/* Size of a reply chunk, configured to exactly allocate 4k bytes */
#define REDIS_REPLY_CHUNK_BYTES (4*1024)
#define REDIS_REPLY_CHUNK_SIZE (REDIS_REPLY_CHUNK_BYTES-sizeof(struct sdshdr)-1-sizeof(size_t))
/* It doesn't make sense to memcpy objects to a chunk when the net result is
* not being able to glue other objects. We want to make sure it can be glued
* to at least a bulk length or \r\n, so set the threshold to be a couple
* of bytes less than the size of the buffer. */
#define REDIS_REPLY_CHUNK_THRESHOLD (REDIS_REPLY_CHUNK_SIZE-16)
/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
#define REDIS_WRITEV_THRESHOLD 3
#define REDIS_WRITEV_THRESHOLD 3
...
@@ -81,7 +73,6 @@
...
@@ -81,7 +73,6 @@
#define REDIS_SET 2
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_ZSET 3
#define REDIS_HASH 4
#define REDIS_HASH 4
#define REDIS_REPLY_NODE 5
#define REDIS_VMPOINTER 8
#define REDIS_VMPOINTER 8
/* Objects encoding. Some kind of objects like Strings and Hashes can be
/* Objects encoding. Some kind of objects like Strings and Hashes can be
...
...
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