summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2016-09-15 09:37:55 +0200
committerantirez <antirez@gmail.com>2016-09-15 09:37:55 +0200
commitbe5439bde3338fadaa5f84afbcc0078d0dbdb44d (patch)
tree536a19cbfcf04812628a6d531aaa74894a02ee0c
parent09a50d34a2e959be6b2fd1c6b7f51cb56c0d29d0 (diff)
downloadredis-be5439bde3338fadaa5f84afbcc0078d0dbdb44d.tar.gz
MEMORY OVERHEAD refactored into a generic API.
-rw-r--r--src/object.c203
1 files changed, 130 insertions, 73 deletions
diff --git a/src/object.c b/src/object.c
index 3b627e90e..8cf86235f 100644
--- a/src/object.c
+++ b/src/object.c
@@ -853,6 +853,120 @@ void objectCommand(client *c) {
}
}
+/* This structure is returned by the getMemoryOverheadData() function in
+ * order to return memory overhead information. */
+struct memoh {
+ size_t total_allocated;
+ size_t startup_allocated;
+ size_t repl_backlog;
+ size_t clients_slaves;
+ size_t clients_normal;
+ size_t aof_buffer;
+ size_t overhead_total;
+ size_t dataset;
+ size_t num_dbs;
+ struct {
+ size_t dbid;
+ size_t overhead_ht_main;
+ size_t overhead_ht_expires;
+ } *db;
+};
+
+/* Release data obtained with getMemoryOverheadData(). */
+void freeMemoryOverheadData(struct memoh *mh) {
+ zfree(mh->db);
+ zfree(mh);
+}
+
+/* Return a struct memoh filled with memory overhead information used
+ * for the MEMORY OVERHEAD and INFO command. The returned structure
+ * pointer should be freed calling freeMemoryOverheadData(). */
+struct memoh *getMemoryOverheadData(void) {
+ int j;
+ size_t mem_total = 0;
+ size_t mem = 0;
+ size_t zmalloc_used = zmalloc_used_memory();
+ struct memoh *mh = zcalloc(sizeof(*mh));
+
+ mh->total_allocated = zmalloc_used;
+ mh->startup_allocated = server.initial_memory_usage;
+ mem_total += server.initial_memory_usage;
+
+ mem = 0;
+ if (server.repl_backlog)
+ mem += zmalloc_size(server.repl_backlog);
+ mh->repl_backlog = 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);
+ }
+ }
+ mh->clients_slaves = 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);
+ }
+ }
+ mh->clients_normal = mem;
+ mem_total+=mem;
+
+ mem = 0;
+ if (server.aof_state != AOF_OFF) {
+ mem += sdslen(server.aof_buf);
+ mem += aofRewriteBufferSize();
+ }
+ mh->aof_buffer = 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;
+
+ mh->db = zrealloc(mh->db,sizeof(mh->db[0])*(mh->num_dbs+1));
+ mh->db[mh->num_dbs].dbid = j;
+
+ mem = dictSize(db->dict) * sizeof(dictEntry) +
+ dictSlots(db->dict) * sizeof(dictEntry*) +
+ dictSize(db->dict) * sizeof(robj);
+ mh->db[mh->num_dbs].overhead_ht_main = mem;
+ mem_total+=mem;
+
+ mem = dictSize(db->expires) * sizeof(dictEntry) +
+ dictSlots(db->expires) * sizeof(dictEntry*);
+ mh->db[mh->num_dbs].overhead_ht_expires = mem;
+ mem_total+=mem;
+
+ mh->num_dbs++;
+ }
+
+ mh->overhead_total = mem_total;
+ mh->dataset = zmalloc_used - mem_total;
+ return mh;
+}
+
/* The memory command will eventually be a complete interface for the
* memory introspection capabilities of Redis.
*
@@ -868,105 +982,48 @@ void memoryCommand(client *c) {
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();
+ struct memoh *mh = getMemoryOverheadData();
- int toplevel_keys = 8;
- void *tlk = addDeferredMultiBulkLength(c);
+ addReplyMultiBulkLen(c,(8+mh->num_dbs)*2);
addReplyBulkCString(c,"total.allocated");
- addReplyLongLong(c,zmalloc_used);
+ addReplyLongLong(c,mh->total_allocated);
addReplyBulkCString(c,"startup.allocated");
- addReplyLongLong(c,server.initial_memory_usage);
- mem_total += server.initial_memory_usage;
+ addReplyLongLong(c,mh->startup_allocated);
- 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);
- }
- }
+ addReplyLongLong(c,mh->repl_backlog);
+
addReplyBulkCString(c,"clients.slaves");
- addReplyLongLong(c,mem);
- mem_total+=mem;
+ addReplyLongLong(c,mh->clients_slaves);
- 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;
+ addReplyLongLong(c,mh->clients_normal);
- 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;
+ addReplyLongLong(c,mh->aof_buffer);
+ for (size_t j = 0; j < mh->num_dbs; j++) {
char dbname[32];
- toplevel_keys++;
- snprintf(dbname,sizeof(dbname),"db.%d",j);
+ snprintf(dbname,sizeof(dbname),"db.%zd",mh->db[j].dbid);
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;
+ addReplyLongLong(c,mh->db[j].overhead_ht_main);
- mem = dictSize(db->expires) * sizeof(dictEntry) +
- dictSlots(db->expires) * sizeof(dictEntry*);
addReplyBulkCString(c,"overhead.hashtable.expires");
- addReplyLongLong(c,mem);
- mem_total+=mem;
+ addReplyLongLong(c,mh->db[j].overhead_ht_expires);
}
addReplyBulkCString(c,"overhead.total");
- addReplyLongLong(c,mem_total);
+ addReplyLongLong(c,mh->overhead_total);
addReplyBulkCString(c,"dataset");
- addReplyLongLong(c,zmalloc_used - mem_total);
+ addReplyLongLong(c,mh->dataset);
- setDeferredMultiBulkLength(c,tlk,toplevel_keys*2);
+ freeMemoryOverheadData(mh);
} else {
addReplyError(c,"Syntax error. Try MEMORY [usage <key>] | [overhead]");
}