提交 ec582cc7 编写于 作者: O Oran Agra

Query buffer shrinking improvements (#5013)

when tracking the peak, don't reset the peak to 0, reset it to the
maximum of the current used, and the planned to be used by the current
arg.

when shrining, split the two separate conditions.
the idle time shrinking will remove all free space.
but the peak based shrinking will keep room for the current arg.

when we resize due to a peak (rahter than idle time), don't trim all
unused space, let the qbuf keep a size that's sufficient for the
currently process bulklen, and the current peak.
Co-authored-by: Nsundb <sundbcn@gmail.com>
Co-authored-by: Nyoav-steinberg <yoav@monfort.co.il>
上级 2248eaac
......@@ -343,6 +343,51 @@ sds sdsRemoveFreeSpace(sds s) {
return s;
}
/* Resize the allocation, this can make the allocation bigger or smaller,
* if the size is smaller than currently used len, the data will be truncated */
sds sdsResize(sds s, size_t size) {
void *sh, *newsh;
char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
size_t len = sdslen(s);
sh = (char*)s-oldhdrlen;
/* Return ASAP if the size is already good. */
if (sdsalloc(s) == size) return s;
/* Truncate len if needed. */
if (size < len) len = size;
/* Check what would be the minimum SDS header that is just good enough to
* fit this string. */
type = sdsReqType(size);
/* Don't use type 5, it is not good for strings that are resized. */
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
hdrlen = sdsHdrSize(type);
/* If the type is the same, or can hold the size in it with low overhead
* (larger than SDS_TYPE_8), we just realloc(), letting the allocator
* to do the copy only if really needed. Otherwise if the change is
* huge, we manually reallocate the string to use the different header
* type. */
if (oldtype==type || (type < oldtype && type > SDS_TYPE_8)) {
newsh = s_realloc(sh, oldhdrlen+size+1);
if (newsh == NULL) return NULL;
s = (char*)newsh+oldhdrlen;
} else {
newsh = s_malloc(hdrlen+size+1);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len);
s_free(sh);
s = (char*)newsh+hdrlen;
s[-1] = type;
}
s[len] = 0;
sdssetlen(s, len);
sdssetalloc(s, size);
return s;
}
/* Return the total size of the allocation of the specified sds string,
* including:
* 1) The sds header before the pointer.
......@@ -1475,6 +1520,34 @@ int sdsTest(int argc, char **argv, int accurate) {
test_cond("sdstemplate() with quoting",
memcmp(x,"v1={value1} {} v2=value2",24) == 0);
sdsfree(x);
/* Test sdsresize - extend */
x = sdsnew("1234567890123456789012345678901234567890");
x = sdsResize(x, 200);
test_cond("sdsrezie() expand len", sdslen(x) == 40);
test_cond("sdsrezie() expand strlen", strlen(x) == 40);
test_cond("sdsrezie() expand alloc", sdsalloc(x) == 200);
/* Test sdsresize - trim free space */
x = sdsResize(x, 80);
test_cond("sdsrezie() shrink len", sdslen(x) == 40);
test_cond("sdsrezie() shrink strlen", strlen(x) == 40);
test_cond("sdsrezie() shrink alloc", sdsalloc(x) == 80);
/* Test sdsresize - crop used space */
x = sdsResize(x, 30);
test_cond("sdsrezie() crop len", sdslen(x) == 30);
test_cond("sdsrezie() crop strlen", strlen(x) == 30);
test_cond("sdsrezie() crop alloc", sdsalloc(x) == 30);
/* Test sdsresize - extend to different class */
x = sdsResize(x, 400);
test_cond("sdsrezie() expand len", sdslen(x) == 30);
test_cond("sdsrezie() expand strlen", strlen(x) == 30);
test_cond("sdsrezie() expand alloc", sdsalloc(x) == 400);
/* Test sdsresize - shrink to different class */
x = sdsResize(x, 4);
test_cond("sdsrezie() crop len", sdslen(x) == 4);
test_cond("sdsrezie() crop strlen", strlen(x) == 4);
test_cond("sdsrezie() crop alloc", sdsalloc(x) == 4);
sdsfree(x);
}
test_report();
return 0;
......
......@@ -267,6 +267,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen);
sds sdsMakeRoomForNonGreedy(sds s, size_t addlen);
void sdsIncrLen(sds s, ssize_t incr);
sds sdsRemoveFreeSpace(sds s);
sds sdsResize(sds s, size_t size);
size_t sdsAllocSize(sds s);
void *sdsAllocPtr(sds s);
......
......@@ -1667,22 +1667,31 @@ int clientsCronResizeQueryBuffer(client *c) {
size_t querybuf_size = sdsalloc(c->querybuf);
time_t idletime = server.unixtime - c->lastinteraction;
/* There are two conditions to resize the query buffer:
* 1) Query buffer is > PROTO_RESIZE_THRESHOLD and too big for latest peak.
* 2) Query buffer is > PROTO_RESIZE_THRESHOLD and client is idle. */
if (querybuf_size > PROTO_RESIZE_THRESHOLD &&
((querybuf_size/(c->querybuf_peak+1)) > 2 ||
idletime > 2))
{
/* Only resize the query buffer if it is actually wasting
* at least a few kbytes. */
if (sdsavail(c->querybuf) > 1024*4) {
/* Only resize the query buffer if the buffer is bigger than
* PROTO_RESIZE_THRESHOLD, and it is actually wasting at least a few kbytes. */
if (querybuf_size > PROTO_RESIZE_THRESHOLD && sdsavail(c->querybuf) > 1024*4) {
/* There are two conditions to resize the query buffer: */
if (idletime > 2) {
/* 1) Query is idle for a long time. */
c->querybuf = sdsRemoveFreeSpace(c->querybuf);
} else if (querybuf_size/2 > c->querybuf_peak) {
/* 2) Query buffer is too big for latest peak. trim excess space but
* only up to a limit, not below the recent peak and current
* c->querybuf (which will be soon get used). */
size_t resize = sdslen(c->querybuf);
if (resize < c->querybuf_peak) resize = c->querybuf_peak;
if (c->bulklen != -1 && resize < (size_t)c->bulklen) resize = c->bulklen;
c->querybuf = sdsResize(c->querybuf, resize);
}
}
/* Reset the peak again to capture the peak memory usage in the next
* cycle. */
c->querybuf_peak = 0;
c->querybuf_peak = sdslen(c->querybuf);
/* We reset to either the current used, or currently processed bulk size,
* which ever is bigger. */
if (c->bulklen != -1 && (size_t)c->bulklen > c->querybuf_peak)
c->querybuf_peak = c->bulklen;
/* Clients representing masters also use a "pending query buffer" that
* is the yet not applied part of the stream we are reading. Such buffer
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册