* Admin/APC(u): fix error in clear cache: if APC(u) runs out of memory clearing just instance cache clear whole cache

This commit is contained in:
Ralf Becker 2016-07-28 12:02:01 +02:00
parent 6f4e65b782
commit 3909c2fdf0
6 changed files with 61 additions and 24 deletions

View File

@ -114,8 +114,7 @@ class admin_hooks
$file['Clear cache and register hooks'] = array( $file['Clear cache and register hooks'] = array(
'id' => 'admin/clear_cache', 'id' => 'admin/clear_cache',
'no_lang' => true, 'no_lang' => true,
'link' => "javascript:egw.message('".lang('Clear cache and register hooks') . "<br />" .lang('Please wait...')."','info'); " . 'link' => "javascript:app.admin.clear_cache();",
"egw.json('admin.admin_hooks.ajax_clear_cache').sendRequest(true);"
); );
} }
@ -164,7 +163,7 @@ class admin_hooks
{ {
$GLOBALS['egw']->redirect_link('/index.php'); $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(); Api\Image::invalidate();

View File

@ -1142,5 +1142,21 @@ app.classes.admin = AppJS.extend(
{ {
this.egw.open_link(_action.data.url, _action.data.target || '_blank', _action.data.popup); 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));
} }
}); });

View File

@ -97,10 +97,12 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd)
* Sends the assembled request to the server * 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 {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 {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 * @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") if(typeof async != "undefined")
{ {
this.async = async; this.async = async;
@ -126,23 +128,31 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd)
dataType: 'json', dataType: 'json',
type: method || 'POST', type: method || 'POST',
success: this.handleResponse, success: this.handleResponse,
error: function(_xmlhttp, _err) { error: error || this.handleError
// 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);
}
}
}); });
return this.request; 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) { json_request.prototype.handleResponse = function(data) {
if (data && typeof data.response != 'undefined') if (data && typeof data.response != 'undefined')
{ {

View File

@ -617,7 +617,7 @@ class Cache
* Flush (delete) whole (instance) cache or application/class specific part of it * Flush (delete) whole (instance) cache or application/class specific part of it
* *
* @param string $level =self::INSTANCE * @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) static public function flush($level=self::INSTANCE, $app=null)
{ {
@ -628,7 +628,7 @@ class Cache
} }
else else
{ {
if (!$provider->flush(self::keys($level, $app))) if (!$provider->flush($app !== "all" ? self::keys($level, $app) : array()))
{ {
if ($level == self::INSTANCE) if ($level == self::INSTANCE)
{ {

View File

@ -144,15 +144,18 @@ class Apc extends Base implements Provider
/** /**
* Delete all data under given keys * 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) * @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) function flush(array $keys)
{ {
// APC >= 3.1.1, but also seems to be missing if apc is disabled eg. for cli // 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; return false;
} }

View File

@ -143,11 +143,20 @@ class Apcu extends Base implements Provider
/** /**
* Delete all data under given keys * Delete all data under given keys
* *
* @param array $keys eg. array($level,$app,$location) * If no keys are given whole APCu cache is cleared, which should allways
* @return boolean true on success, false on error (eg. $key not set) * 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) function flush(array $keys)
{ {
if (!$keys && function_exists('apcu_clear_cache'))
{
apcu_clear_cache();
return true;
}
// APCu > 5 has APCUIterator // APCu > 5 has APCUIterator
if (class_exists('APCUIterator')) if (class_exists('APCUIterator'))
{ {
@ -160,7 +169,7 @@ class Apcu extends Base implements Provider
} }
else else
{ {
if (function_exists('apcu_clear_cache')) apcu_clear_cache (); if (function_exists('apcu_clear_cache')) apcu_clear_cache();
return false; return false;
} }