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
Hide whitespace changes
Inline
Side-by-side
src/networking.c
View file @
36c19d03
...
...
@@ -13,13 +13,9 @@ int listMatchObjects(void *a, void *b) {
redisClient
*
createClient
(
int
fd
)
{
redisClient
*
c
;
/* Make sure to allocate a multiple of the page size to prevent wasting
* memory. A page size of 4096 is assumed here. We need to compensate
* for the zmalloc overhead of sizeof(size_t) bytes. */
size_t
size
=
8192
-
sizeof
(
size_t
);
redisAssert
(
size
>
sizeof
(
redisClient
));
c
=
zmalloc
(
size
);
c
->
buflen
=
size
-
sizeof
(
redisClient
);
/* Allocate more space to hold a static write buffer. */
c
=
zmalloc
(
sizeof
(
redisClient
)
+
REDIS_REPLY_CHUNK_BYTES
);
c
->
buflen
=
REDIS_REPLY_CHUNK_BYTES
;
c
->
bufpos
=
0
;
anetNonBlock
(
NULL
,
fd
);
...
...
@@ -71,40 +67,95 @@ int _ensureFileEvent(redisClient *c) {
return
REDIS_OK
;
}
void
_addReplyObjectToList
(
redisClient
*
c
,
robj
*
obj
)
{
redisAssert
(
obj
->
type
==
REDIS_STRING
&&
obj
->
encoding
==
REDIS_ENCODING_RAW
);
listAddNodeTail
(
c
->
reply
,
obj
);
/* Create a duplicate of the last object in the reply list when
* it is not exclusively owned by the reply list. */
robj
*
dupLastObjectIfNeeded
(
list
*
reply
)
{
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
)
{
sds
buffer
=
sdsnewlen
(
NULL
,
REDIS_REPLY_CHUNK_SIZE
);
sdsupdatelen
(
buffer
);
/* sdsnewlen expects non-empty string */
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_REPLY_NODE
,
buffer
));
int
_addReplyToBuffer
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
size_t
available
=
c
->
buflen
-
c
->
bufpos
;
/* 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
)
{
size_t
available
=
0
;
redisAssert
(
len
<
REDIS_REPLY_CHUNK_THRESHOLD
);
if
(
listLength
(
c
->
reply
)
>
0
)
{
robj
*
o
=
listNodeValue
(
listLast
(
c
->
reply
));
/* Make sure to append to a reply node with enough bytes available. */
if
(
o
->
type
==
REDIS_REPLY_NODE
)
available
=
sdsavail
(
o
->
ptr
);
if
(
o
->
type
!=
REDIS_REPLY_NODE
||
len
>
available
)
{
_ensureBufferInReplyList
(
c
);
_addReplyStringToBuffer
(
c
,
s
,
len
);
void
_addReplyObjectToList
(
redisClient
*
c
,
robj
*
o
)
{
robj
*
tail
;
if
(
listLength
(
c
->
reply
)
==
0
)
{
incrRefCount
(
o
);
listAddNodeTail
(
c
->
reply
,
o
);
}
else
{
tail
=
listNodeValue
(
listLast
(
c
->
reply
));
/* Append to this object when possible. */
if
(
tail
->
ptr
!=
NULL
&&
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
{
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
{
available
=
c
->
buflen
-
c
->
bufpos
;
if
(
len
>
available
)
{
_ensureBufferInReplyList
(
c
);
_addReplyStringToBuffer
(
c
,
s
,
len
);
tail
=
listNodeValue
(
listLast
(
c
->
reply
));
/* Append to this object when possible. */
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
{
memcpy
(
c
->
buf
+
c
->
bufpos
,
s
,
len
);
c
->
bufpos
+=
len
;
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
s
));
}
}
}
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) {
/* This increments the refcount. */
obj
=
getDecodedObject
(
obj
);
}
if
(
sdslen
(
obj
->
ptr
)
<
REDIS_REPLY_CHUNK_THRESHOLD
)
{
_addReplyStringToBuffer
(
c
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
));
decrRefCount
(
obj
);
}
else
{
if
(
_addReplyToBuffer
(
c
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
))
!=
REDIS_OK
)
_addReplyObjectToList
(
c
,
obj
);
}
decrRefCount
(
obj
);
}
void
addReplySds
(
redisClient
*
c
,
sds
s
)
{
...
...
@@ -133,28 +180,25 @@ void addReplySds(redisClient *c, sds s) {
sdsfree
(
s
);
return
;
}
if
(
sdslen
(
s
)
<
REDIS_REPLY_CHUNK_THRESHOLD
)
{
_addReplyStringToBuffer
(
c
,
s
,
sdslen
(
s
));
if
(
_addReplyToBuffer
(
c
,
s
,
sdslen
(
s
))
==
REDIS_OK
)
{
sdsfree
(
s
);
}
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
)
{
if
(
_ensureFileEvent
(
c
)
!=
REDIS_OK
)
return
;
if
(
len
<
REDIS_REPLY_CHUNK_THRESHOLD
)
{
_addReplyStringToBuffer
(
c
,
s
,
len
);
}
else
{
_addReplyObjectToList
(
c
,
createStringObject
(
s
,
len
));
}
if
(
_addReplyToBuffer
(
c
,
s
,
len
)
!=
REDIS_OK
)
_addReplyStringToList
(
c
,
s
,
len
);
}
/* Adds an empty object to the reply list that will contain the multi bulk
* length, which is not known when this function is called. */
void
*
addDeferredMultiBulkLength
(
redisClient
*
c
)
{
if
(
_ensureFileEvent
(
c
)
!=
REDIS_OK
)
return
NULL
;
_addReplyObjectToList
(
c
,
createObject
(
REDIS_STRING
,
NULL
));
listAddNodeTail
(
c
->
reply
,
createObject
(
REDIS_STRING
,
NULL
));
return
listLast
(
c
->
reply
);
}
...
...
@@ -170,9 +214,10 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
len
->
ptr
=
sdscatprintf
(
sdsempty
(),
"*%ld
\r\n
"
,
length
);
if
(
ln
->
next
!=
NULL
)
{
next
=
listNodeValue
(
ln
->
next
);
/* Only glue when the next node is a reply chunk. */
if
(
next
->
type
==
REDIS_REPLY_NODE
)
{
len
->
ptr
=
sdscatlen
(
len
->
ptr
,
next
->
ptr
,
sdslen
(
next
->
ptr
));
/* Only glue when the next node is an sds */
if
(
next
->
ptr
!=
NULL
)
{
len
->
ptr
=
sdscat
(
len
->
ptr
,
next
->
ptr
);
listDelNode
(
c
->
reply
,
ln
->
next
);
}
}
...
...
src/object.c
View file @
36c19d03
...
...
@@ -196,7 +196,6 @@ void decrRefCount(void *obj) {
case
REDIS_SET
:
freeSetObject
(
o
);
break
;
case
REDIS_ZSET
:
freeZsetObject
(
o
);
break
;
case
REDIS_HASH
:
freeHashObject
(
o
);
break
;
case
REDIS_REPLY_NODE
:
freeStringObject
(
o
);
break
;
default:
redisPanic
(
"Unknown object type"
);
break
;
}
o
->
ptr
=
NULL
;
/* defensive programming. We'll see NULL in traces. */
...
...
src/redis.h
View file @
36c19d03
...
...
@@ -47,15 +47,7 @@
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
#define REDIS_SHARED_INTEGERS 10000
/* 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)
#define REDIS_REPLY_CHUNK_BYTES (5*1500)
/* 5 TCP packets with default MTU */
/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
#define REDIS_WRITEV_THRESHOLD 3
...
...
@@ -81,7 +73,6 @@
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4
#define REDIS_REPLY_NODE 5
#define REDIS_VMPOINTER 8
/* 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