提交 0edd38e5 编写于 作者: Y Yossi Gottlieb

Add minmemory-os configuration parameter.

上级 e4375727
......@@ -322,6 +322,12 @@ slave-priority 100
#
# maxmemory-samples 3
# Define the minimum OS memory threshold allowed before eviction begins. This
# is checked perioedically and eviction will be attempted for 1/2 of the delta
# between the free memory and required spare. If 0 is specified, this is
# disabled.
# minmemory-os 0
############################## APPEND ONLY MODE ###############################
# By default Redis asynchronously dumps the dataset on disk. This mode is
......
......@@ -197,6 +197,8 @@ void loadServerConfigFromString(char *config) {
}
} else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
server.maxmemory = memtoll(argv[1],NULL);
} else if (!strcasecmp(argv[0],"minmemory-os") && argc == 2) {
server.minmemory_os = memtoll(argv[1],NULL);
} else if (!strcasecmp(argv[0],"maxmemory-policy") && argc == 2) {
if (!strcasecmp(argv[1],"volatile-lru")) {
server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
......@@ -493,7 +495,7 @@ void configSetCommand(redisClient *c) {
if (server.maxmemory < zmalloc_used_memory()) {
redisLog(REDIS_WARNING,"WARNING: the new maxmemory value set via CONFIG SET is smaller than the current memory usage. This will result in keys eviction and/or inability to accept new write commands depending on the maxmemory-policy.");
}
freeMemoryIfNeeded();
freeMemoryIfNeeded(server.maxmemory);
}
} else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-policy")) {
if (!strcasecmp(o->ptr,"volatile-lru")) {
......
......@@ -794,6 +794,84 @@ void clientsCron(void) {
}
}
#ifdef __linux__
long long int getFreeOSMemory(void) {
FILE *meminfo_file;
char buf[128];
long long int memfree_value = -1;
long long int buffers_value = -1;
long long int cached_value = -1;
long long int memfree = -1;
meminfo_file = fopen("/proc/meminfo", "r");
if (!meminfo_file)
return -1;
while (fgets(buf, sizeof(buf)-1, meminfo_file) != NULL) {
char *p = NULL;
char *k;
char *arg;
if (!(k = strtok_r(buf, " ", &p)))
break; /* parse error */
if (!(arg = strtok_r(NULL, " ", &p)))
break; /* parse error */
if (strcmp(k, "MemFree:") == 0) {
memfree_value = strtoull(arg, &p, 10);
if (!p || *p != '\0')
memfree_value = -1; /* parse error */
} else if (strcmp(k, "Buffers:") == 0) {
buffers_value = strtoull(arg, &p, 10);
if (!p || *p != '\0')
buffers_value = -1; /* parse error */
} else if (strcmp(k, "Cached:") == 0) {
cached_value = strtoull(arg, &p, 10);
if (!p || *p != '\0')
cached_value = -1; /* parse error */
}
if (memfree_value != -1 &&
buffers_value != -1 &&
cached_value != -1) {
memfree = memfree_value + buffers_value + cached_value;
break;
}
}
fclose(meminfo_file);
if (memfree > 0)
memfree *= 1024;
return memfree;
}
#else
#error "Implement getFreeOSMemory for this platform first."
#endif
void checkOSMemory(void) {
/* Called periodically if minmemory_os is defined, and verifies that
* enough free OS memory is reported. If not, it attempts to free 1/2
* of the minmemory_os value.
*/
long long int os_memfree;
if (!server.minmemory_os)
return;
os_memfree = getFreeOSMemory();
if (os_memfree < 0)
return;
if ((unsigned long long) os_memfree < server.minmemory_os) {
long long int delta = server.minmemory_os - os_memfree;
if ((long long int) zmalloc_used_memory() > (delta / 2)) {
redisLog(REDIS_WARNING, "OS Memory is low, trying to free %llu bytes.", delta / 2);
freeMemoryIfNeeded(zmalloc_used_memory() - (delta / 2));
} else {
redisLog(REDIS_WARNING, "OS Memory is low, but this redis is too small to attempt eviction.");
}
}
}
/* This is our timer interrupt, called REDIS_HZ times per second.
* Here is where we do a number of things that need to be done asynchronously.
* For instance:
......@@ -856,6 +934,11 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
redisLog(REDIS_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information");
}
/* Try to evict if OS memory is low */
run_with_period(10000) {
checkOSMemory();
}
/* Cancel draining mode if not polled for a long time */
if (server.draining && server.unixtime - server.last_drain_time >= 10)
server.draining = 0;
......@@ -1636,7 +1719,7 @@ int processCommand(redisClient *c) {
* keys in the dataset). If there are not the only thing we can do
* is returning an error. */
if (server.maxmemory) {
int retval = freeMemoryIfNeeded();
int retval = freeMemoryIfNeeded(server.maxmemory);
if ((c->cmd->flags & REDIS_CMD_DENYOOM) && retval == REDIS_ERR) {
flagTransaction(c);
addReply(c, shared.oomerr);
......@@ -2321,7 +2404,7 @@ void hideconnectionCommand(redisClient *c) {
* should block the execution of commands that will result in more memory
* used by the server.
*/
int freeMemoryIfNeeded(void) {
int freeMemoryIfNeeded(unsigned long long maxmemory) {
size_t mem_used, mem_tofree, mem_freed;
int slaves = listLength(server.slaves);
......@@ -2348,13 +2431,13 @@ int freeMemoryIfNeeded(void) {
}
/* Check if we are over the memory limit. */
if (mem_used <= server.maxmemory) return REDIS_OK;
if (mem_used <= maxmemory) return REDIS_OK;
if (server.maxmemory_policy == REDIS_MAXMEMORY_NO_EVICTION)
return REDIS_ERR; /* We need to free memory, but policy forbids. */
/* Compute how much memory we need to free. */
mem_tofree = mem_used - server.maxmemory;
mem_tofree = mem_used - maxmemory;
mem_freed = 0;
while (mem_freed < mem_tofree) {
int j, k, keys_freed = 0;
......
......@@ -650,6 +650,7 @@ struct redisServer {
/* Limits */
unsigned int maxclients; /* Max number of simultaneous clients */
unsigned long long maxmemory; /* Max number of memory bytes to use */
unsigned long long minmemory_os; /* OS Free memory threshold that */
int maxmemory_policy; /* Policy for key evition */
int maxmemory_samples; /* Pricision of random sampling */
/* Blocked clients */
......@@ -969,7 +970,7 @@ unsigned int zsetLength(robj *zobj);
void zsetConvert(robj *zobj, int encoding);
/* Core functions */
int freeMemoryIfNeeded(void);
int freeMemoryIfNeeded(unsigned long long maxmemory);
int processCommand(redisClient *c);
void setupSignalHandlers(void);
struct redisCommand *lookupCommand(sds name);
......
......@@ -278,7 +278,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
if (server.maxmemory && server.lua_write_dirty == 0 &&
(cmd->flags & REDIS_CMD_DENYOOM))
{
if (freeMemoryIfNeeded() == REDIS_ERR) {
if (freeMemoryIfNeeded(server.maxmemory) == REDIS_ERR) {
luaPushError(lua, shared.oomerr->ptr);
goto cleanup;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册