summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2016-09-13 17:39:22 +0200
committerantirez <antirez@gmail.com>2016-09-13 17:39:25 +0200
commit8c84c962cfb6359401c2df92f79d7e848a34802f (patch)
tree91dd7fefa9e30efb5e42da65c526301258ea6b04
parent89dec6921d8fa0ffa0226b9f4d99f373d4d16cfd (diff)
downloadredis-8c84c962cfb6359401c2df92f79d7e848a34802f.tar.gz
MEMORY OVERHEAD implemented (using Oran Agra initial implementation).
This code was extracted from @oranagra PR #3223 and modified in order to provide only certain amounts of information compared to the original code. It was also moved from DEBUG to the newly introduced MEMORY command. Thanks to Oran for the implementation and the PR. It implements detailed memory usage stats that can be useful in both provisioning and troubleshooting memory usage in Redis.
-rw-r--r--src/object.c102
-rw-r--r--src/server.c3
-rw-r--r--src/server.h1
3 files changed, 104 insertions, 2 deletions
diff --git a/src/object.c b/src/object.c
index cb5d1818c..3b627e90e 100644
--- a/src/object.c
+++ b/src/object.c
@@ -867,7 +867,107 @@ void memoryCommand(client *c) {
usage += sdsAllocSize(c->argv[1]->ptr);
usage += sizeof(dictEntry);
addReplyLongLong(c,usage);
+ } else if (!strcasecmp(c->argv[1]->ptr,"overhead") && c->argc == 2) {
+ int j;
+ size_t mem_total = 0;
+ size_t mem = 0;
+ size_t zmalloc_used = zmalloc_used_memory();
+
+ int toplevel_keys = 8;
+ void *tlk = addDeferredMultiBulkLength(c);
+
+ addReplyBulkCString(c,"total.allocated");
+ addReplyLongLong(c,zmalloc_used);
+
+ addReplyBulkCString(c,"startup.allocated");
+ addReplyLongLong(c,server.initial_memory_usage);
+ mem_total += server.initial_memory_usage;
+
+ mem = 0;
+ if (server.repl_backlog)
+ mem += zmalloc_size(server.repl_backlog);
+ addReplyBulkCString(c,"replication.backlog");
+ addReplyLongLong(c,mem);
+ mem_total += mem;
+
+ mem = 0;
+ if (listLength(server.slaves)) {
+ listIter li;
+ listNode *ln;
+
+ listRewind(server.slaves,&li);
+ while((ln = listNext(&li))) {
+ client *client = listNodeValue(ln);
+ mem += getClientOutputBufferMemoryUsage(client);
+ mem += sdsAllocSize(client->querybuf);
+ mem += sizeof(client);
+ }
+ }
+ addReplyBulkCString(c,"clients.slaves");
+ addReplyLongLong(c,mem);
+ mem_total+=mem;
+
+ mem = 0;
+ if (listLength(server.clients)) {
+ listIter li;
+ listNode *ln;
+
+ listRewind(server.clients,&li);
+ while((ln = listNext(&li))) {
+ client *client = listNodeValue(ln);
+ if (client->flags & CLIENT_SLAVE)
+ continue;
+ mem += getClientOutputBufferMemoryUsage(client);
+ mem += sdsAllocSize(client->querybuf);
+ mem += sizeof(client);
+ }
+ }
+ addReplyBulkCString(c,"clients.normal");
+ addReplyLongLong(c,mem);
+ mem_total+=mem;
+
+ mem = 0;
+ if (server.aof_state != AOF_OFF) {
+ mem += sdslen(server.aof_buf);
+ mem += aofRewriteBufferSize();
+ }
+ addReplyBulkCString(c,"aof.buffer");
+ addReplyLongLong(c,mem);
+ mem_total+=mem;
+
+ for (j = 0; j < server.dbnum; j++) {
+ redisDb *db = server.db+j;
+ long long keyscount = dictSize(db->dict);
+ if (keyscount==0) continue;
+
+ char dbname[32];
+ toplevel_keys++;
+ snprintf(dbname,sizeof(dbname),"db.%d",j);
+ addReplyBulkCString(c,dbname);
+ addReplyMultiBulkLen(c,4);
+
+ mem = dictSize(db->dict) * sizeof(dictEntry) +
+ dictSlots(db->dict) * sizeof(dictEntry*) +
+ dictSize(db->dict) * sizeof(robj);
+ addReplyBulkCString(c,"overhead.hashtable.main");
+ addReplyLongLong(c,mem);
+ mem_total+=mem;
+
+ mem = dictSize(db->expires) * sizeof(dictEntry) +
+ dictSlots(db->expires) * sizeof(dictEntry*);
+ addReplyBulkCString(c,"overhead.hashtable.expires");
+ addReplyLongLong(c,mem);
+ mem_total+=mem;
+ }
+
+ addReplyBulkCString(c,"overhead.total");
+ addReplyLongLong(c,mem_total);
+
+ addReplyBulkCString(c,"dataset");
+ addReplyLongLong(c,zmalloc_used - mem_total);
+
+ setDeferredMultiBulkLength(c,tlk,toplevel_keys*2);
} else {
- addReplyError(c,"Syntax error. Try MEMORY usage <key>");
+ addReplyError(c,"Syntax error. Try MEMORY [usage <key>] | [overhead]");
}
}
diff --git a/src/server.c b/src/server.c
index d143bf0c8..91c17f650 100644
--- a/src/server.c
+++ b/src/server.c
@@ -274,7 +274,7 @@ struct redisCommand redisCommandTable[] = {
{"readwrite",readwriteCommand,1,"F",0,NULL,0,0,0,0,0},
{"dump",dumpCommand,2,"r",0,NULL,1,1,1,0,0},
{"object",objectCommand,3,"r",0,NULL,2,2,2,0,0},
- {"memory",memoryCommand,3,"r",0,NULL,0,0,0,0,0},
+ {"memory",memoryCommand,-2,"r",0,NULL,0,0,0,0,0},
{"client",clientCommand,-2,"as",0,NULL,0,0,0,0,0},
{"eval",evalCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
{"evalsha",evalShaCommand,-3,"s",0,evalGetKeys,0,0,0,0,0},
@@ -1860,6 +1860,7 @@ void initServer(void) {
slowlogInit();
latencyMonitorInit();
bioInit();
+ server.initial_memory_usage = zmalloc_used_memory();
}
/* Populates the Redis Command Table starting from the hard coded list
diff --git a/src/server.h b/src/server.h
index 281989107..0d104425c 100644
--- a/src/server.h
+++ b/src/server.h
@@ -801,6 +801,7 @@ struct redisServer {
int cronloops; /* Number of times the cron function run */
char runid[CONFIG_RUN_ID_SIZE+1]; /* ID always different at every exec. */
int sentinel_mode; /* True if this instance is a Sentinel. */
+ size_t initial_memory_usage; /* Bytes used after initialization. */
/* Modules */
dict *moduleapi; /* Exported APIs dictionary for modules. */
list *loadmodule_queue; /* List of modules to load at startup. */