Merge commit 'cbcd07777dc569618a34f59e5fd0de53178f4f1d' into unstable

Former-commit-id: 49784c8122e827bd9de86bbae4d88c313400e86e
This commit is contained in:
John Sully 2020-05-21 18:48:49 -04:00
commit 3384af024d
9 changed files with 76 additions and 46 deletions

View File

@ -943,13 +943,20 @@ replica-priority 100
# In all the above cases the default is to delete objects in a blocking way, # In all the above cases the default is to delete objects in a blocking way,
# like if DEL was called. However you can configure each case specifically # like if DEL was called. However you can configure each case specifically
# in order to instead release memory in a non-blocking way like if UNLINK # in order to instead release memory in a non-blocking way like if UNLINK
# was called, using the following configuration directives: # was called, using the following configuration directives.
lazyfree-lazy-eviction no lazyfree-lazy-eviction no
lazyfree-lazy-expire no lazyfree-lazy-expire no
lazyfree-lazy-server-del no lazyfree-lazy-server-del no
replica-lazy-flush no replica-lazy-flush no
# It is also possible, for the case when to replace the user code DEL calls
# with UNLINK calls is not easy, to modify the default behavior of the DEL
# command to act exactly like UNLINK, using the following configuration
# directive:
lazyfree-lazy-user-del no
################################ THREADED I/O ################################# ################################ THREADED I/O #################################
# Redis is mostly single threaded, however there are certain threaded # Redis is mostly single threaded, however there are certain threaded

View File

@ -1849,18 +1849,18 @@ void aclCommand(client *c) {
} }
} else if (!strcasecmp(sub,"help")) { } else if (!strcasecmp(sub,"help")) {
const char *help[] = { const char *help[] = {
"LOAD -- Reload users from the ACL file.", "LOAD -- Reload users from the ACL file.",
"SAVE -- Save the current config to the ACL file." "SAVE -- Save the current config to the ACL file.",
"LIST -- Show user details in config file format.", "LIST -- Show user details in config file format.",
"USERS -- List all the registered usernames.", "USERS -- List all the registered usernames.",
"SETUSER <username> [attribs ...] -- Create or modify a user.", "SETUSER <username> [attribs ...] -- Create or modify a user.",
"GETUSER <username> -- Get the user details.", "GETUSER <username> -- Get the user details.",
"DELUSER <username> [...] -- Delete a list of users.", "DELUSER <username> [...] -- Delete a list of users.",
"CAT -- List available categories.", "CAT -- List available categories.",
"CAT <category> -- List commands inside category.", "CAT <category> -- List commands inside category.",
"GENPASS -- Generate a secure user password.", "GENPASS -- Generate a secure user password.",
"WHOAMI -- Return the current connection username.", "WHOAMI -- Return the current connection username.",
"LOG [<count> | RESET] -- Show the ACL log entries.", "LOG [<count> | RESET] -- Show the ACL log entries.",
NULL NULL
}; };
addReplyHelp(c,help); addReplyHelp(c,help);

View File

@ -660,7 +660,7 @@ void delGenericCommand(client *c, int lazy) {
} }
void delCommand(client *c) { void delCommand(client *c) {
delGenericCommand(c,0); delGenericCommand(c,g_pserver->lazyfree_lazy_user_del);
} }
void unlinkCommand(client *c) { void unlinkCommand(client *c) {

View File

@ -178,6 +178,8 @@ client *createClient(connection *conn, int iel) {
memset(c->uuid, 0, UUID_BINARY_LEN); memset(c->uuid, 0, UUID_BINARY_LEN);
c->client_tracking_prefixes = NULL; 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 = NULL;
c->auth_callback_privdata = NULL; c->auth_callback_privdata = NULL;
c->auth_module = NULL; c->auth_module = NULL;
@ -1577,6 +1579,11 @@ bool freeClient(client *c) {
listDelNode(g_pserver->clients_to_close,ln); listDelNode(g_pserver->clients_to_close,ln);
} }
/* Remove the contribution that this client gave to our
* incrementally computed memory usage. */
g_pserver->stat_clients_type_memory[c->client_cron_last_memory_type] -=
c->client_cron_last_memory_usage;
/* Release other dynamically allocated client structure fields, /* Release other dynamically allocated client structure fields,
* and finally release the client structure itself. */ * and finally release the client structure itself. */
zfree(c->bufAsync); zfree(c->bufAsync);

View File

@ -1025,32 +1025,15 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
mh->repl_backlog = mem; mh->repl_backlog = mem;
mem_total += mem; mem_total += mem;
mem = 0; /* Computing the memory used by the clients would be O(N) if done
if (listLength(g_pserver->clients)) { * here online. We use our values computed incrementally by
listIter li; * clientsCronTrackClientsMemUsage(). */
listNode *ln; mh->clients_slaves = g_pserver->stat_clients_type_memory[CLIENT_TYPE_SLAVE];
size_t mem_normal = 0, mem_slaves = 0; mh->clients_normal = g_pserver->stat_clients_type_memory[CLIENT_TYPE_MASTER]+
g_pserver->stat_clients_type_memory[CLIENT_TYPE_PUBSUB]+
listRewind(g_pserver->clients,&li); g_pserver->stat_clients_type_memory[CLIENT_TYPE_NORMAL];
while((ln = listNext(&li))) { mem_total += mh->clients_slaves;
size_t mem_curr = 0; mem_total += mh->clients_normal;
client *c = (client*)listNodeValue(ln);
std::unique_lock<fastlock> ul(c->lock);
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;
mem = 0; mem = 0;
if (g_pserver->aof_state != AOF_OFF) { if (g_pserver->aof_state != AOF_OFF) {

View File

@ -1236,10 +1236,7 @@ int rdbSaveRio(rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) {
if (rdbSaveType(rdb,RDB_OPCODE_SELECTDB) == -1) goto werr; if (rdbSaveType(rdb,RDB_OPCODE_SELECTDB) == -1) goto werr;
if (rdbSaveLen(rdb,j) == -1) goto werr; if (rdbSaveLen(rdb,j) == -1) goto werr;
/* Write the RESIZE DB opcode. We trim the size to UINT32_MAX, which /* Write the RESIZE DB opcode. */
* is currently the largest type we are able to represent in RDB sizes.
* However this does not limit the actual size of the DB to load since
* these sizes are just hints to resize the hash tables. */
uint64_t db_size, expires_size; uint64_t db_size, expires_size;
db_size = dictSize(db->pdict); db_size = dictSize(db->pdict);
expires_size = db->setexpire->size(); expires_size = db->setexpire->size();

View File

@ -972,6 +972,7 @@ int luaLogCommand(lua_State *lua) {
lua_pushstring(lua, "Invalid debug level."); lua_pushstring(lua, "Invalid debug level.");
return lua_error(lua); return lua_error(lua);
} }
if (level < cserver.verbosity) return 0;
/* Glue together all the arguments */ /* Glue together all the arguments */
log = sdsempty(); log = sdsempty();

View File

@ -1632,6 +1632,28 @@ int clientsCronTrackExpansiveClients(client *c) {
return 0; /* This function never terminates the client. */ 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. */
g_pserver->stat_clients_type_memory[c->client_cron_last_memory_type] -=
c->client_cron_last_memory_usage;
g_pserver->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 /* Return the max samples in the memory usage of clients tracked by
* the function clientsCronTrackExpansiveClients(). */ * the function clientsCronTrackExpansiveClients(). */
void getExpansiveClientsInfo(size_t *in_usage, size_t *out_usage) { void getExpansiveClientsInfo(size_t *in_usage, size_t *out_usage) {
@ -1695,6 +1717,7 @@ void clientsCron(int iel) {
if (clientsCronHandleTimeout(c,now)) continue; // Client free'd so don't release the lock if (clientsCronHandleTimeout(c,now)) continue; // Client free'd so don't release the lock
if (clientsCronResizeQueryBuffer(c)) goto LContinue; if (clientsCronResizeQueryBuffer(c)) goto LContinue;
if (clientsCronTrackExpansiveClients(c)) goto LContinue; if (clientsCronTrackExpansiveClients(c)) goto LContinue;
if (clientsCronTrackClientsMemUsage(c)) goto LContinue;
LContinue: LContinue:
fastlock_unlock(&c->lock); fastlock_unlock(&c->lock);
} }
@ -3042,6 +3065,8 @@ void initServer(void) {
g_pserver->stat_rdb_cow_bytes = 0; g_pserver->stat_rdb_cow_bytes = 0;
g_pserver->stat_aof_cow_bytes = 0; g_pserver->stat_aof_cow_bytes = 0;
g_pserver->stat_module_cow_bytes = 0; g_pserver->stat_module_cow_bytes = 0;
for (int j = 0; j < CLIENT_TYPE_COUNT; j++)
g_pserver->stat_clients_type_memory[j] = 0;
g_pserver->cron_malloc_stats.zmalloc_used = 0; g_pserver->cron_malloc_stats.zmalloc_used = 0;
g_pserver->cron_malloc_stats.process_rss = 0; g_pserver->cron_malloc_stats.process_rss = 0;
g_pserver->cron_malloc_stats.allocator_allocated = 0; g_pserver->cron_malloc_stats.allocator_allocated = 0;

View File

@ -450,6 +450,7 @@ public:
#define CLIENT_TYPE_SLAVE 1 /* Slaves. */ #define CLIENT_TYPE_SLAVE 1 /* Slaves. */
#define CLIENT_TYPE_PUBSUB 2 /* Clients subscribed to PubSub channels. */ #define CLIENT_TYPE_PUBSUB 2 /* Clients subscribed to PubSub channels. */
#define CLIENT_TYPE_MASTER 3 /* Master. */ #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 #define CLIENT_TYPE_OBUF_COUNT 3 /* Number of clients to expose to output
buffer configuration. Just the first buffer configuration. Just the first
three: normal, replica, pubsub. */ three: normal, replica, pubsub. */
@ -1292,10 +1293,10 @@ typedef struct client {
* when the authenticated user * when the authenticated user
* changes. */ * changes. */
void *auth_callback_privdata; /* Private data that is passed when the auth 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. */ * Redis Core. */
void *auth_module; /* The module that owns the callback, which is used 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.*/ * unloaded for cleanup. Opaque for Redis Core.*/
/* UUID announced by the client (default nil) - used to detect multiple connections to/from the same peer */ /* UUID announced by the client (default nil) - used to detect multiple connections to/from the same peer */
@ -1310,6 +1311,13 @@ typedef struct client {
rax *client_tracking_prefixes; /* A dictionary of prefixes we are already rax *client_tracking_prefixes; /* A dictionary of prefixes we are already
subscribed to in BCAST mode, in the subscribed to in BCAST mode, in the
context of client side caching. */ 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 */ /* Response buffer */
int bufpos; int bufpos;
char buf[PROTO_REPLY_CHUNK_BYTES]; char buf[PROTO_REPLY_CHUNK_BYTES];
@ -1709,6 +1717,7 @@ struct redisServer {
size_t stat_rdb_cow_bytes; /* Copy on write bytes during RDB saving. */ 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_aof_cow_bytes; /* Copy on write bytes during AOF rewrite. */
size_t stat_module_cow_bytes; /* Copy on write bytes during module fork. */ 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 */ 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 /* The following two are used to track instantaneous metrics, like
* number of operations per second, network traffic. */ * number of operations per second, network traffic. */
@ -1940,6 +1949,7 @@ struct redisServer {
int lazyfree_lazy_eviction; int lazyfree_lazy_eviction;
int lazyfree_lazy_expire; int lazyfree_lazy_expire;
int lazyfree_lazy_server_del; int lazyfree_lazy_server_del;
int lazyfree_lazy_user_del;
/* Latency monitor */ /* Latency monitor */
long long latency_monitor_threshold; long long latency_monitor_threshold;
dict *latency_events; dict *latency_events;