mirror of
https://github.com/fluencelabs/redis
synced 2025-03-19 17:10:50 +00:00
MEMORY OVERHEAD refactored into a generic API.
This commit is contained in:
parent
09a50d34a2
commit
be5439bde3
201
src/object.c
201
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
|
/* The memory command will eventually be a complete interface for the
|
||||||
* memory introspection capabilities of Redis.
|
* memory introspection capabilities of Redis.
|
||||||
*
|
*
|
||||||
@ -868,105 +982,48 @@ void memoryCommand(client *c) {
|
|||||||
usage += sizeof(dictEntry);
|
usage += sizeof(dictEntry);
|
||||||
addReplyLongLong(c,usage);
|
addReplyLongLong(c,usage);
|
||||||
} else if (!strcasecmp(c->argv[1]->ptr,"overhead") && c->argc == 2) {
|
} else if (!strcasecmp(c->argv[1]->ptr,"overhead") && c->argc == 2) {
|
||||||
int j;
|
struct memoh *mh = getMemoryOverheadData();
|
||||||
size_t mem_total = 0;
|
|
||||||
size_t mem = 0;
|
|
||||||
size_t zmalloc_used = zmalloc_used_memory();
|
|
||||||
|
|
||||||
int toplevel_keys = 8;
|
addReplyMultiBulkLen(c,(8+mh->num_dbs)*2);
|
||||||
void *tlk = addDeferredMultiBulkLength(c);
|
|
||||||
|
|
||||||
addReplyBulkCString(c,"total.allocated");
|
addReplyBulkCString(c,"total.allocated");
|
||||||
addReplyLongLong(c,zmalloc_used);
|
addReplyLongLong(c,mh->total_allocated);
|
||||||
|
|
||||||
addReplyBulkCString(c,"startup.allocated");
|
addReplyBulkCString(c,"startup.allocated");
|
||||||
addReplyLongLong(c,server.initial_memory_usage);
|
addReplyLongLong(c,mh->startup_allocated);
|
||||||
mem_total += server.initial_memory_usage;
|
|
||||||
|
|
||||||
mem = 0;
|
|
||||||
if (server.repl_backlog)
|
|
||||||
mem += zmalloc_size(server.repl_backlog);
|
|
||||||
addReplyBulkCString(c,"replication.backlog");
|
addReplyBulkCString(c,"replication.backlog");
|
||||||
addReplyLongLong(c,mem);
|
addReplyLongLong(c,mh->repl_backlog);
|
||||||
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");
|
addReplyBulkCString(c,"clients.slaves");
|
||||||
addReplyLongLong(c,mem);
|
addReplyLongLong(c,mh->clients_slaves);
|
||||||
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");
|
addReplyBulkCString(c,"clients.normal");
|
||||||
addReplyLongLong(c,mem);
|
addReplyLongLong(c,mh->clients_normal);
|
||||||
mem_total+=mem;
|
|
||||||
|
|
||||||
mem = 0;
|
|
||||||
if (server.aof_state != AOF_OFF) {
|
|
||||||
mem += sdslen(server.aof_buf);
|
|
||||||
mem += aofRewriteBufferSize();
|
|
||||||
}
|
|
||||||
addReplyBulkCString(c,"aof.buffer");
|
addReplyBulkCString(c,"aof.buffer");
|
||||||
addReplyLongLong(c,mem);
|
addReplyLongLong(c,mh->aof_buffer);
|
||||||
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;
|
|
||||||
|
|
||||||
|
for (size_t j = 0; j < mh->num_dbs; j++) {
|
||||||
char dbname[32];
|
char dbname[32];
|
||||||
toplevel_keys++;
|
snprintf(dbname,sizeof(dbname),"db.%zd",mh->db[j].dbid);
|
||||||
snprintf(dbname,sizeof(dbname),"db.%d",j);
|
|
||||||
addReplyBulkCString(c,dbname);
|
addReplyBulkCString(c,dbname);
|
||||||
addReplyMultiBulkLen(c,4);
|
addReplyMultiBulkLen(c,4);
|
||||||
|
|
||||||
mem = dictSize(db->dict) * sizeof(dictEntry) +
|
|
||||||
dictSlots(db->dict) * sizeof(dictEntry*) +
|
|
||||||
dictSize(db->dict) * sizeof(robj);
|
|
||||||
addReplyBulkCString(c,"overhead.hashtable.main");
|
addReplyBulkCString(c,"overhead.hashtable.main");
|
||||||
addReplyLongLong(c,mem);
|
addReplyLongLong(c,mh->db[j].overhead_ht_main);
|
||||||
mem_total+=mem;
|
|
||||||
|
|
||||||
mem = dictSize(db->expires) * sizeof(dictEntry) +
|
|
||||||
dictSlots(db->expires) * sizeof(dictEntry*);
|
|
||||||
addReplyBulkCString(c,"overhead.hashtable.expires");
|
addReplyBulkCString(c,"overhead.hashtable.expires");
|
||||||
addReplyLongLong(c,mem);
|
addReplyLongLong(c,mh->db[j].overhead_ht_expires);
|
||||||
mem_total+=mem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addReplyBulkCString(c,"overhead.total");
|
addReplyBulkCString(c,"overhead.total");
|
||||||
addReplyLongLong(c,mem_total);
|
addReplyLongLong(c,mh->overhead_total);
|
||||||
|
|
||||||
addReplyBulkCString(c,"dataset");
|
addReplyBulkCString(c,"dataset");
|
||||||
addReplyLongLong(c,zmalloc_used - mem_total);
|
addReplyLongLong(c,mh->dataset);
|
||||||
|
|
||||||
setDeferredMultiBulkLength(c,tlk,toplevel_keys*2);
|
freeMemoryOverheadData(mh);
|
||||||
} else {
|
} else {
|
||||||
addReplyError(c,"Syntax error. Try MEMORY [usage <key>] | [overhead]");
|
addReplyError(c,"Syntax error. Try MEMORY [usage <key>] | [overhead]");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user