Get the memory status from the point of view of the maxmemory directive: * if the memory used is under the maxmemory setting then C_OK is returned. * Otherwise, if we are over the memory limit, the function returns * C_ERR. * * The function may return additional info via reference, only if the * pointers to the respective arguments is not NULL. Certain fields are * populated only when C_ERR
| 398 | * (Populated when C_ERR is returned) |
| 399 | */ |
| 400 | int getMaxmemoryState(size_t *total, size_t *logical, size_t *tofree, float *level, EvictReason *reason, bool fQuickCycle, bool fPreSnapshot) { |
| 401 | size_t mem_reported, mem_used, mem_tofree; |
| 402 | |
| 403 | /* Check if we are over the memory usage limit. If we are not, no need |
| 404 | * to subtract the slaves output buffers. We can just return ASAP. */ |
| 405 | mem_reported = zmalloc_used_memory(); |
| 406 | if (total) *total = mem_reported; |
| 407 | size_t maxmemory = g_pserver->maxmemory; |
| 408 | if (fPreSnapshot) |
| 409 | maxmemory = static_cast<size_t>(maxmemory*0.9); // derate memory by 10% since we won't be able to free during snapshot |
| 410 | if (g_pserver->FRdbSaveInProgress() && !cserver.fForkBgSave) |
| 411 | maxmemory = static_cast<size_t>(maxmemory*1.2); |
| 412 | |
| 413 | /* If available system memory is below a certain threshold, force eviction */ |
| 414 | long long sys_available_mem_buffer = 0; |
| 415 | if (g_pserver->force_eviction_percent && g_pserver->cron_malloc_stats.sys_total) { |
| 416 | float available_mem_ratio = (float)(100 - g_pserver->force_eviction_percent)/100; |
| 417 | size_t min_available_mem = static_cast<size_t>(g_pserver->cron_malloc_stats.sys_total * available_mem_ratio); |
| 418 | sys_available_mem_buffer = static_cast<long>(g_pserver->cron_malloc_stats.sys_available - min_available_mem); |
| 419 | if (sys_available_mem_buffer < 0) { |
| 420 | long long mem_threshold = mem_reported + sys_available_mem_buffer; |
| 421 | maxmemory = ((long long)maxmemory < mem_threshold) ? maxmemory : static_cast<size_t>(mem_threshold); |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | /* We may return ASAP if there is no need to compute the level. */ |
| 426 | int return_ok_asap = !maxmemory || mem_reported <= maxmemory; |
| 427 | if (return_ok_asap && !level) return C_OK; |
| 428 | |
| 429 | /* Remove the size of slaves output buffers and AOF buffer from the |
| 430 | * count of used memory. */ |
| 431 | mem_used = mem_reported; |
| 432 | size_t overhead = freeMemoryGetNotCountedMemory(); |
| 433 | mem_used = (mem_used > overhead) ? mem_used-overhead : 0; |
| 434 | |
| 435 | /* If system available memory is too low, we want to force evictions no matter |
| 436 | * what so we also offset the overhead from maxmemory. */ |
| 437 | if (sys_available_mem_buffer < 0) { |
| 438 | maxmemory = (maxmemory > overhead) ? maxmemory-overhead : 0; |
| 439 | } |
| 440 | |
| 441 | /* Compute the ratio of memory usage. */ |
| 442 | if (level) { |
| 443 | if (!maxmemory) { |
| 444 | *level = 0; |
| 445 | } else { |
| 446 | *level = (float)mem_used / (float)maxmemory; |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | if (return_ok_asap) return C_OK; |
| 451 | |
| 452 | /* Check if we are still over the memory limit. */ |
| 453 | if (mem_used <= maxmemory) return C_OK; |
| 454 | |
| 455 | /* Compute how much memory we need to free. */ |
| 456 | mem_tofree = mem_used - maxmemory; |
| 457 | if (g_pserver->m_pstorageFactory && !fQuickCycle) |
no test coverage detected