summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSalvatore Sanfilippo <antirez@gmail.com>2020-05-04 10:20:31 +0200
committerGitHub <noreply@github.com>2020-05-04 10:20:31 +0200
commitb3f3d5a42fec96bb062feb2cc6f5e79d7039b874 (patch)
tree1945a66f276a9877528b15202f2489803a6663e3
parent57697373efcc5189d67d53955f1df609ebbb9a8d (diff)
parent6726b3c2cb41e700c8cfd2f821df6c8c847a5ddc (diff)
downloadredis-b3f3d5a42fec96bb062feb2cc6f5e79d7039b874.tar.gz
Merge pull request #7176 from oranagra/fix-optimize-reply-buffer
optimize memory usage of deferred replies - fixed
-rw-r--r--src/networking.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/src/networking.c b/src/networking.c
index c4a277e0a..d62533e3e 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -436,6 +436,34 @@ void addReplyStatusFormat(client *c, const char *fmt, ...) {
sdsfree(s);
}
+/* Sometimes we are forced to create a new reply node, and we can't append to
+ * the previous one, when that happens, we wanna try to trim the unused space
+ * at the end of the last reply node which we won't use anymore. */
+void trimReplyUnusedTailSpace(client *c) {
+ listNode *ln = listLast(c->reply);
+ clientReplyBlock *tail = ln? listNodeValue(ln): NULL;
+
+ /* Note that 'tail' may be NULL even if we have a tail node, becuase when
+ * addDeferredMultiBulkLength() is used */
+ if (!tail) return;
+
+ /* We only try to trim the space is relatively high (more than a 1/4 of the
+ * allocation), otherwise there's a high chance realloc will NOP.
+ * Also, to avoid large memmove which happens as part of realloc, we only do
+ * that if the used part is small. */
+ if (tail->size - tail->used > tail->size / 4 &&
+ tail->used < PROTO_REPLY_CHUNK_BYTES)
+ {
+ size_t old_size = tail->size;
+ tail = zrealloc(tail, tail->used + sizeof(clientReplyBlock));
+ /* take over the allocation's internal fragmentation (at least for
+ * memory usage tracking) */
+ tail->size = zmalloc_usable(tail) - sizeof(clientReplyBlock);
+ c->reply_bytes += tail->size - old_size;
+ listNodeValue(ln) = tail;
+ }
+}
+
/* 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 *addReplyDeferredLen(client *c) {
@@ -443,6 +471,7 @@ void *addReplyDeferredLen(client *c) {
* ready to be sent, since we are sure that before returning to the
* event loop setDeferredAggregateLen() will be called. */
if (prepareClientToWrite(c) != C_OK) return NULL;
+ trimReplyUnusedTailSpace(c);
listAddNodeTail(c->reply,NULL); /* NULL is our placeholder. */
return listLast(c->reply);
}