From 96caf6effd60968fde8f8749f4e8ff84cbae3268 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 28 Jul 2016 12:02:01 +0200 Subject: [PATCH] * Admin/APC(u): fix error in clear cache: if APC(u) runs out of memory clearing just instance cache clear whole cache --- admin/inc/class.admin_hooks.inc.php | 5 ++-- admin/js/app.js | 16 +++++++++++++ api/js/jsapi/egw_json.js | 36 ++++++++++++++++++----------- api/src/Cache.php | 4 ++-- api/src/Cache/Apc.php | 9 +++++--- api/src/Cache/Apcu.php | 15 +++++++++--- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/admin/inc/class.admin_hooks.inc.php b/admin/inc/class.admin_hooks.inc.php index 4323d3a972..71d762a1a3 100644 --- a/admin/inc/class.admin_hooks.inc.php +++ b/admin/inc/class.admin_hooks.inc.php @@ -114,8 +114,7 @@ class admin_hooks $file['Clear cache and register hooks'] = array( 'id' => 'admin/clear_cache', 'no_lang' => true, - 'link' => "javascript:egw.message('".lang('Clear cache and register hooks') . "
" .lang('Please wait...')."','info'); " . - "egw.json('admin.admin_hooks.ajax_clear_cache').sendRequest(true);" + 'link' => "javascript:app.admin.clear_cache();", ); } @@ -164,7 +163,7 @@ class admin_hooks { $GLOBALS['egw']->redirect_link('/index.php'); } - Api\Cache::flush(Api\Cache::INSTANCE); + Api\Cache::flush(Api\Cache::INSTANCE, !empty($_GET['errored']) ? "all" : null); Api\Image::invalidate(); diff --git a/admin/js/app.js b/admin/js/app.js index 7c68256b6e..1038772d09 100644 --- a/admin/js/app.js +++ b/admin/js/app.js @@ -1142,5 +1142,21 @@ app.classes.admin = AppJS.extend( { this.egw.open_link(_action.data.url, _action.data.target || '_blank', _action.data.popup); } + }, + + /** + * Clear instance cache + * + * If there is an error on server-side, resend request with an parameter allowing + * cache to use different method not requiring eg. so much memory + */ + clear_cache: function() + { + this.egw.message(this.egw.lang('Clear cache and register hooks')+"\n"+this.egw.lang('Please wait...'),'info'); + + this.egw.json('admin.admin_hooks.ajax_clear_cache').sendRequest(true, undefined, jQuery.proxy(function(_xmlhttp, _err) + { + this.egw.json('admin.admin_hooks.ajax_clear_cache&errored=1').sendRequest(true); + }, this)); } }); diff --git a/api/js/jsapi/egw_json.js b/api/js/jsapi/egw_json.js index 6018ead926..d3f05e77fc 100644 --- a/api/js/jsapi/egw_json.js +++ b/api/js/jsapi/egw_json.js @@ -97,10 +97,12 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd) * Sends the assembled request to the server * @param {boolean} [async=false] Overrides async provided in constructor to give an easy way to make simple async requests * @param {string} method ='POST' allow to eg. use a (cachable) 'GET' request instead of POST + * @param {function} error option error callback(_xmlhttp, _err) used instead our default this.error * * @return {jqXHR} jQuery jqXHR request object */ - json_request.prototype.sendRequest = function(async,method) { + json_request.prototype.sendRequest = function(async, method, error) + { if(typeof async != "undefined") { this.async = async; @@ -126,23 +128,31 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd) dataType: 'json', type: method || 'POST', success: this.handleResponse, - error: function(_xmlhttp, _err) { - // Don't error about an abort - if(_err !== 'abort') - { - this.egw.message.call(this.egw, this.egw.lang('A request to the EGroupware server returned with an error')+': '+_xmlhttp.statusText+' ('+_xmlhttp.status+ - ")\n\n"+this.egw.lang('Please reload the EGroupware desktop (F5 / Cmd+r).')+"\n"+ - this.egw.lang('If the error persists, contact your administrator for help and ask to check the error-log of the webserver.')+ - "\n\nURL: "+this.url+"\n"+(_xmlhttp.getAllResponseHeaders() ? _xmlhttp.getAllResponseHeaders().match(/^Date:.*$/m)[0]:'')); - - this.egw.debug('error', 'Ajax request to', this.url, ' failed: ', _err, _xmlhttp.status, _xmlhttp.statusText); - } - } + error: error || this.handleError }); return this.request; }; + /** + * Default error callback displaying error via egw.message + * + * @param {XMLHTTP} _xmlhttp + * @param {string} _err + */ + json_request.prototype.handleError = function(_xmlhttp, _err) { + // Don't error about an abort + if(_err !== 'abort') + { + this.egw.message.call(this.egw, this.egw.lang('A request to the EGroupware server returned with an error')+': '+_xmlhttp.statusText+' ('+_xmlhttp.status+ + ")\n\n"+this.egw.lang('Please reload the EGroupware desktop (F5 / Cmd+r).')+"\n"+ + this.egw.lang('If the error persists, contact your administrator for help and ask to check the error-log of the webserver.')+ + "\n\nURL: "+this.url+"\n"+(_xmlhttp.getAllResponseHeaders() ? _xmlhttp.getAllResponseHeaders().match(/^Date:.*$/m)[0]:'')); + + this.egw.debug('error', 'Ajax request to', this.url, ' failed: ', _err, _xmlhttp.status, _xmlhttp.statusText); + } + }; + json_request.prototype.handleResponse = function(data) { if (data && typeof data.response != 'undefined') { diff --git a/api/src/Cache.php b/api/src/Cache.php index 6b856ffefa..9759969759 100644 --- a/api/src/Cache.php +++ b/api/src/Cache.php @@ -617,7 +617,7 @@ class Cache * Flush (delete) whole (instance) cache or application/class specific part of it * * @param string $level =self::INSTANCE - * @param string $app =null + * @param string $app =null app-name or "all" to empty complete cache */ static public function flush($level=self::INSTANCE, $app=null) { @@ -628,7 +628,7 @@ class Cache } else { - if (!$provider->flush(self::keys($level, $app))) + if (!$provider->flush($app !== "all" ? self::keys($level, $app) : array())) { if ($level == self::INSTANCE) { diff --git a/api/src/Cache/Apc.php b/api/src/Cache/Apc.php index a29ea40db3..8971005753 100644 --- a/api/src/Cache/Apc.php +++ b/api/src/Cache/Apc.php @@ -144,15 +144,18 @@ class Apc extends Base implements Provider /** * Delete all data under given keys * + * If no keys are given whole APC cache is cleared, which should allways + * work and can not run out of memory as the iterator sometimes does. + * * @param array $keys eg. array($level,$app,$location) - * @return boolean true on success, false on error (eg. $key not set) + * @return boolean true on success, false on error (eg. on iterator available) */ function flush(array $keys) { // APC >= 3.1.1, but also seems to be missing if apc is disabled eg. for cli - if (!class_exists('APCIterator')) + if (!class_exists('APCIterator') || !$keys) { - if (function_exists('apc_clear_cache')) apc_clear_cache ('user'); + if (function_exists('apc_clear_cache')) apc_clear_cache('user'); return false; } diff --git a/api/src/Cache/Apcu.php b/api/src/Cache/Apcu.php index 2d58bc3e5a..f18f9c998a 100644 --- a/api/src/Cache/Apcu.php +++ b/api/src/Cache/Apcu.php @@ -143,11 +143,20 @@ class Apcu extends Base implements Provider /** * Delete all data under given keys * - * @param array $keys eg. array($level,$app,$location) - * @return boolean true on success, false on error (eg. $key not set) + * If no keys are given whole APCu cache is cleared, which should allways + * work and can not run out of memory as the iterator sometimes does. + * + * @param array $keys eg. array($level,$app,$location) or array() to clear whole cache + * @return boolean true on success, false on error (eg. on iterator available) */ function flush(array $keys) { + if (!$keys && function_exists('apcu_clear_cache')) + { + apcu_clear_cache(); + + return true; + } // APCu > 5 has APCUIterator if (class_exists('APCUIterator')) { @@ -160,7 +169,7 @@ class Apcu extends Base implements Provider } else { - if (function_exists('apcu_clear_cache')) apcu_clear_cache (); + if (function_exists('apcu_clear_cache')) apcu_clear_cache(); return false; }