From 037ea6f36076f9f213cec2f305b8a395f4f40897 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 28 Mar 2013 13:34:59 +0400 Subject: [PATCH] Reimplemented OPcache restart trigger. Now, if memory or hash are full the restart is scheduled only in case the amount of wasted memory is above opcache.max_wasted_percentage. Otherwise OPcahce continue serving the following requests using already cached files, but doesn't try to add new files (the cache is full anyway). --- ext/opcache/ZendAccelerator.c | 52 ++++++++++++++++----------- ext/opcache/ZendAccelerator.h | 3 +- ext/opcache/zend_accelerator_module.c | 3 -- ext/opcache/zend_shared_alloc.c | 15 +++++++- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index a5f99235f1..5d5de443d3 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -184,6 +184,13 @@ static inline char* accel_getcwd(int *cwd_len TSRMLS_DC) } } +void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason TSRMLS_DC) +{ + if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) { + zend_accel_schedule_restart(reason TSRMLS_CC); + } +} + /* O+ tracks changes of "include_path" directive. It stores all the requested * values in ZCG(include_paths) shared hash table, current value in * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in @@ -219,8 +226,10 @@ static ZEND_INI_MH(accel_include_path_on_modify) key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries; ZCG(include_path_key) = key + ZCG(include_path_len) + 1; zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key)); - } - } + } else { + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); + } + } zend_shared_alloc_unlock(TSRMLS_C); SHM_PROTECT(); @@ -868,14 +877,6 @@ static inline int do_validate_timestamps(zend_persistent_script *persistent_scri return FAILURE; } -static void zend_accel_schedule_restart_if_necessary(TSRMLS_D) -{ - if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) { - ZSMMG(memory_exhausted) = 1; - zend_accel_schedule_restart(ACCEL_RESTART_WASTED TSRMLS_CC); - } -} - static inline int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle TSRMLS_DC) { if (ZCG(accel_directives).revalidate_freq && @@ -973,7 +974,9 @@ char *accel_make_persistent_key_ex(zend_file_handle *file_handle, int path_lengt zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key)); include_path = ZCG(include_path_key); include_path_len = 1; - } + } else { + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); + } } zend_shared_alloc_unlock(TSRMLS_C); @@ -1051,12 +1054,14 @@ static void zend_accel_add_key(char *key, unsigned int key_length, zend_accel_ha if (zend_accel_hash_is_full(&ZCSG(hash))) { zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!"); ZSMMG(memory_exhausted) = 1; - zend_accel_schedule_restart(ACCEL_RESTART_HASH TSRMLS_CC); + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC); } else { char *new_key = zend_shared_alloc(key_length + 1); if (new_key) { memcpy(new_key, key, key_length + 1); zend_accel_hash_update(&ZCSG(hash), new_key, key_length + 1, 1, bucket); + } else { + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); } } } @@ -1078,7 +1083,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr if (zend_accel_hash_is_full(&ZCSG(hash))) { zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!"); ZSMMG(memory_exhausted) = 1; - zend_accel_schedule_restart(ACCEL_RESTART_HASH TSRMLS_CC); + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC); zend_shared_alloc_unlock(TSRMLS_C); return new_persistent_script; } @@ -1106,6 +1111,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr /* Allocate shared memory */ ZCG(mem) = zend_shared_alloc(memory_used); if (!ZCG(mem)) { + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); zend_shared_alloc_unlock(TSRMLS_C); return new_persistent_script; } @@ -1139,7 +1145,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr if (!zend_accel_hash_update(&ZCSG(hash), key, key_length + 1, 1, bucket)) { zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!"); ZSMMG(memory_exhausted) = 1; - zend_accel_schedule_restart(ACCEL_RESTART_HASH TSRMLS_CC); + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH TSRMLS_CC); } } @@ -1503,7 +1509,11 @@ static zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int persistent_script->corrupted = 1; persistent_script->timestamp = 0; ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption; - zend_accel_schedule_restart_if_necessary(TSRMLS_C); + if (ZSMMG(memory_exhausted)) { + zend_accel_restart_reason reason = + zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM; + zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC); + } } zend_shared_alloc_unlock(TSRMLS_C); persistent_script = NULL; @@ -1524,7 +1534,11 @@ static zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int persistent_script->corrupted = 1; persistent_script->timestamp = 0; ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption; - zend_accel_schedule_restart_if_necessary(TSRMLS_C); + if (ZSMMG(memory_exhausted)) { + zend_accel_restart_reason reason = + zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM; + zend_accel_schedule_restart_if_necessary(reason TSRMLS_CC); + } } zend_shared_alloc_unlock(TSRMLS_C); persistent_script = NULL; @@ -2011,9 +2025,6 @@ static void accel_activate(void) case ACCEL_RESTART_OOM: ZCSG(oom_restarts)++; break; - case ACCEL_RESTART_WASTED: - ZCSG(wasted_restarts)++; - break; case ACCEL_RESTART_HASH: ZCSG(hash_restarts)++; break; @@ -2380,7 +2391,6 @@ static void zend_accel_init_shm(TSRMLS_D) zend_reset_cache_vars(TSRMLS_C); ZCSG(oom_restarts) = 0; - ZCSG(wasted_restarts) = 0; ZCSG(hash_restarts) = 0; ZCSG(manual_restarts) = 0; @@ -2530,6 +2540,8 @@ static int accel_startup(zend_extension *extension) key[ZCG(include_path_len) + 1] = 'A' + ZCSG(include_paths).num_entries; ZCG(include_path_key) = key + ZCG(include_path_len) + 1; zend_accel_hash_update(&ZCSG(include_paths), key, ZCG(include_path_len) + 1, 0, ZCG(include_path_key)); + } else { + zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM TSRMLS_CC); } zend_shared_alloc_unlock(TSRMLS_C); } diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index f9b51b0df8..f2005473b1 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -167,7 +167,6 @@ typedef time_t accel_time_t; typedef enum _zend_accel_restart_reason { ACCEL_RESTART_OOM, /* restart because of out of memory */ - ACCEL_RESTART_WASTED, /* restart because of wasted memory */ ACCEL_RESTART_HASH, /* restart because of hash overflow */ ACCEL_RESTART_USER /* restart sheduled by opcache_reset() */ } zend_accel_restart_reason; @@ -268,7 +267,6 @@ typedef struct _zend_accel_shared_globals { unsigned long misses; unsigned long blacklist_misses; unsigned long oom_restarts; /* number of restarts because of out of memory */ - unsigned long wasted_restarts; /* number of restarts because of wasted memory */ unsigned long hash_restarts; /* number of restarts because of hash overflow */ unsigned long manual_restarts; /* number of restarts sheduled by opcache_reset() */ zend_accel_hash hash; /* hash table for cached scripts */ @@ -319,6 +317,7 @@ extern zend_accel_globals accel_globals; extern char *zps_api_failure_reason; void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC); +void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason TSRMLS_DC); int accelerator_shm_read_lock(TSRMLS_D); void accelerator_shm_read_unlock(TSRMLS_D); diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 8cfab79fad..8d6ed4ee27 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -406,8 +406,6 @@ void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS) php_info_print_table_row(2, "Max keys", buf); snprintf(buf, sizeof(buf), "%ld", ZCSG(oom_restarts)); php_info_print_table_row(2, "OOM restarts", buf); - snprintf(buf, sizeof(buf), "%ld", ZCSG(wasted_restarts)); - php_info_print_table_row(2, "Wasted memory restarts", buf); snprintf(buf, sizeof(buf), "%ld", ZCSG(hash_restarts)); php_info_print_table_row(2, "Hash keys restarts", buf); snprintf(buf, sizeof(buf), "%ld", ZCSG(manual_restarts)); @@ -535,7 +533,6 @@ static ZEND_FUNCTION(opcache_get_status) add_assoc_long(statistics, "start_time", ZCSG(start_time)); add_assoc_long(statistics, "last_restart_time", ZCSG(last_restart_time)); add_assoc_long(statistics, "oom_restarts", ZCSG(oom_restarts)); - add_assoc_long(statistics, "wasted_restarts", ZCSG(wasted_restarts)); add_assoc_long(statistics, "hash_restarts", ZCSG(hash_restarts)); add_assoc_long(statistics, "manual_restarts", ZCSG(manual_restarts)); add_assoc_long(statistics, "misses", ZSMMG(memory_exhausted)?ZCSG(misses):ZCSG(misses)-ZCSG(blacklist_misses)); diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 18e8bdb1f4..ebfdea276d 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -215,8 +215,17 @@ int zend_shared_alloc_startup(int requested_size) /* move shared_segments and shared_free to shared memory */ ZCG(locked) = 1; /* no need to perform a real lock at this point */ p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals)); + if (!p_tmp_shared_globals) { + zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); + return ALLOC_FAILURE;; + } tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *)); + if (!tmp_shared_segments) { + zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); + return ALLOC_FAILURE;; + } + copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)()); *p_tmp_shared_globals = tmp_shared_globals; @@ -226,6 +235,11 @@ int zend_shared_alloc_startup(int requested_size) ZSMMG(shared_segments) = tmp_shared_segments; ZSMMG(shared_memory_state).positions = (int *)zend_shared_alloc(sizeof(int) * ZSMMG(shared_segments_count)); + if (!ZSMMG(shared_memory_state).positions) { + zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); + return ALLOC_FAILURE;; + } + ZCG(locked) = 0; return res; @@ -277,7 +291,6 @@ static size_t zend_shared_alloc_get_largest_free_block(void) zend_accel_error(ACCEL_LOG_WARNING, "Not enough free shared space to allocate %ld bytes (%ld bytes free)", (long)size, (long)ZSMMG(shared_free)); \ if (zend_shared_alloc_get_largest_free_block() < MIN_FREE_MEMORY) { \ ZSMMG(memory_exhausted) = 1; \ - zend_accel_schedule_restart(ACCEL_RESTART_OOM TSRMLS_CC); \ } \ } while (0) -- 2.40.0