summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/networking.c7
-rw-r--r--src/object.c33
-rw-r--r--src/server.c25
-rw-r--r--src/server.h13
4 files changed, 52 insertions, 26 deletions
diff --git a/src/networking.c b/src/networking.c
index 85c640e34..654fda517 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -157,6 +157,8 @@ client *createClient(connection *conn) {
c->client_list_node = NULL;
c->client_tracking_redirection = 0;
c->client_tracking_prefixes = NULL;
+ c->client_cron_last_memory_usage = 0;
+ c->client_cron_last_memory_type = CLIENT_TYPE_NORMAL;
c->auth_callback = NULL;
c->auth_callback_privdata = NULL;
c->auth_module = NULL;
@@ -1160,6 +1162,11 @@ void freeClient(client *c) {
listDelNode(server.clients_to_close,ln);
}
+ /* Remove the contribution that this client gave to our
+ * incrementally computed memory usage. */
+ server.stat_clients_type_memory[c->client_cron_last_memory_type] -=
+ c->client_cron_last_memory_usage;
+
/* Release other dynamically allocated client structure fields,
* and finally release the client structure itself. */
if (c->name) decrRefCount(c->name);
diff --git a/src/object.c b/src/object.c
index 11e335afc..52d5b11f5 100644
--- a/src/object.c
+++ b/src/object.c
@@ -974,30 +974,15 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
mh->repl_backlog = mem;
mem_total += mem;
- mem = 0;
- if (listLength(server.clients)) {
- listIter li;
- listNode *ln;
- size_t mem_normal = 0, mem_slaves = 0;
-
- listRewind(server.clients,&li);
- while((ln = listNext(&li))) {
- size_t mem_curr = 0;
- client *c = listNodeValue(ln);
- int type = getClientType(c);
- mem_curr += getClientOutputBufferMemoryUsage(c);
- mem_curr += sdsAllocSize(c->querybuf);
- mem_curr += sizeof(client);
- if (type == CLIENT_TYPE_SLAVE)
- mem_slaves += mem_curr;
- else
- mem_normal += mem_curr;
- }
- mh->clients_slaves = mem_slaves;
- mh->clients_normal = mem_normal;
- mem = mem_slaves + mem_normal;
- }
- mem_total+=mem;
+ /* Computing the memory used by the clients would be O(N) if done
+ * here online. We use our values computed incrementally by
+ * clientsCronTrackClientsMemUsage(). */
+ mh->clients_slaves = server.stat_clients_type_memory[CLIENT_TYPE_SLAVE];
+ mh->clients_normal = server.stat_clients_type_memory[CLIENT_TYPE_MASTER]+
+ server.stat_clients_type_memory[CLIENT_TYPE_PUBSUB]+
+ server.stat_clients_type_memory[CLIENT_TYPE_NORMAL];
+ mem_total += mh->clients_slaves;
+ mem_total += mh->clients_normal;
mem = 0;
if (server.aof_state != AOF_OFF) {
diff --git a/src/server.c b/src/server.c
index 56feb09a3..996e0f5d2 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1593,6 +1593,28 @@ int clientsCronTrackExpansiveClients(client *c) {
return 0; /* This function never terminates the client. */
}
+/* Iterating all the clients in getMemoryOverheadData() is too slow and
+ * in turn would make the INFO command too slow. So we perform this
+ * computation incrementally and track the (not instantaneous but updated
+ * to the second) total memory used by clients using clinetsCron() in
+ * a more incremental way (depending on server.hz). */
+int clientsCronTrackClientsMemUsage(client *c) {
+ size_t mem = 0;
+ int type = getClientType(c);
+ mem += getClientOutputBufferMemoryUsage(c);
+ mem += sdsAllocSize(c->querybuf);
+ mem += sizeof(client);
+ /* Now that we have the memory used by the client, remove the old
+ * value from the old categoty, and add it back. */
+ server.stat_clients_type_memory[c->client_cron_last_memory_type] -=
+ c->client_cron_last_memory_usage;
+ server.stat_clients_type_memory[type] += mem;
+ /* Remember what we added and where, to remove it next time. */
+ c->client_cron_last_memory_usage = mem;
+ c->client_cron_last_memory_type = type;
+ return 0;
+}
+
/* Return the max samples in the memory usage of clients tracked by
* the function clientsCronTrackExpansiveClients(). */
void getExpansiveClientsInfo(size_t *in_usage, size_t *out_usage) {
@@ -1653,6 +1675,7 @@ void clientsCron(void) {
if (clientsCronHandleTimeout(c,now)) continue;
if (clientsCronResizeQueryBuffer(c)) continue;
if (clientsCronTrackExpansiveClients(c)) continue;
+ if (clientsCronTrackClientsMemUsage(c)) continue;
}
}
@@ -2792,6 +2815,8 @@ void initServer(void) {
server.stat_rdb_cow_bytes = 0;
server.stat_aof_cow_bytes = 0;
server.stat_module_cow_bytes = 0;
+ for (int j = 0; j < CLIENT_TYPE_COUNT; j++)
+ server.stat_clients_type_memory[j] = 0;
server.cron_malloc_stats.zmalloc_used = 0;
server.cron_malloc_stats.process_rss = 0;
server.cron_malloc_stats.allocator_allocated = 0;
diff --git a/src/server.h b/src/server.h
index 9b77f55ac..cf4c285f8 100644
--- a/src/server.h
+++ b/src/server.h
@@ -274,6 +274,7 @@ typedef long long ustime_t; /* microsecond time type. */
#define CLIENT_TYPE_SLAVE 1 /* Slaves. */
#define CLIENT_TYPE_PUBSUB 2 /* Clients subscribed to PubSub channels. */
#define CLIENT_TYPE_MASTER 3 /* Master. */
+#define CLIENT_TYPE_COUNT 4 /* Total number of client types. */
#define CLIENT_TYPE_OBUF_COUNT 3 /* Number of clients to expose to output
buffer configuration. Just the first
three: normal, slave, pubsub. */
@@ -820,10 +821,10 @@ typedef struct client {
* when the authenticated user
* changes. */
void *auth_callback_privdata; /* Private data that is passed when the auth
- * changed callback is executed. Opaque for
+ * changed callback is executed. Opaque for
* Redis Core. */
void *auth_module; /* The module that owns the callback, which is used
- * to disconnect the client if the module is
+ * to disconnect the client if the module is
* unloaded for cleanup. Opaque for Redis Core.*/
/* If this client is in tracking mode and this field is non zero,
@@ -833,6 +834,13 @@ typedef struct client {
rax *client_tracking_prefixes; /* A dictionary of prefixes we are already
subscribed to in BCAST mode, in the
context of client side caching. */
+ /* In clientsCronTrackClientsMemUsage() we track the memory usage of
+ * each client and add it to the sum of all the clients of a given type,
+ * however we need to remember what was the old contribution of each
+ * client, and in which categoty the client was, in order to remove it
+ * before adding it the new value. */
+ uint64_t client_cron_last_memory_usage;
+ int client_cron_last_memory_type;
/* Response buffer */
int bufpos;
char buf[PROTO_REPLY_CHUNK_BYTES];
@@ -1129,6 +1137,7 @@ struct redisServer {
size_t stat_rdb_cow_bytes; /* Copy on write bytes during RDB saving. */
size_t stat_aof_cow_bytes; /* Copy on write bytes during AOF rewrite. */
size_t stat_module_cow_bytes; /* Copy on write bytes during module fork. */
+ uint64_t stat_clients_type_memory[CLIENT_TYPE_COUNT];/* Mem usage by type */
long long stat_unexpected_error_replies; /* Number of unexpected (aof-loading, replica to master, etc.) error replies */
/* The following two are used to track instantaneous metrics, like
* number of operations per second, network traffic. */