diff options
author | mistic100 <mistic@piwigo.org> | 2014-05-24 14:18:04 +0000 |
---|---|---|
committer | mistic100 <mistic@piwigo.org> | 2014-05-24 14:18:04 +0000 |
commit | fea2a4efd1ad085def7cf84cc444325d0815b62e (patch) | |
tree | 892dcb971d34efd7cbff6c31375448a09dfbe73b | |
parent | 59f418f7986594895a2352e8895250069cff336a (diff) |
feature 3077 : improve cache invalidation
- add "lastmodified" automatic field for categories, groups, users, tags and images tables
- provide a "server key" to the client cache manager
git-svn-id: http://piwigo.org/svn/trunk@28532 68402e56-0260-453c-a942-63ccdbb3a9ee
Diffstat (limited to '')
-rw-r--r-- | admin/batch_manager_global.php | 11 | ||||
-rw-r--r-- | admin/batch_manager_unit.php | 5 | ||||
-rw-r--r-- | admin/cat_perm.php | 6 | ||||
-rw-r--r-- | admin/include/functions.php | 61 | ||||
-rw-r--r-- | admin/picture_modify.php | 6 | ||||
-rw-r--r-- | admin/themes/default/js/LocalStorageCache.js | 22 | ||||
-rw-r--r-- | admin/themes/default/template/batch_manager_global.tpl | 35 | ||||
-rw-r--r-- | admin/themes/default/template/batch_manager_unit.tpl | 35 | ||||
-rw-r--r-- | admin/themes/default/template/cat_perm.tpl | 84 | ||||
-rw-r--r-- | admin/themes/default/template/picture_modify.tpl | 49 | ||||
-rw-r--r-- | install/db/141-database.php | 45 | ||||
-rw-r--r-- | install/piwigo_structure-mysql.sql | 20 |
12 files changed, 263 insertions, 116 deletions
diff --git a/admin/batch_manager_global.php b/admin/batch_manager_global.php index 57cb2acdf..4bec501db 100644 --- a/admin/batch_manager_global.php +++ b/admin/batch_manager_global.php @@ -701,12 +701,11 @@ SELECT id,path,representative_ext,file,filesize,level,name,width,height,rotation $template->assign('thumb_params', $thumb_params); } -$template->assign( - array( - 'nb_thumbs_page' => $nb_thumbs_page, - 'nb_thumbs_set' => count($page['cat_elements_id']), - ) - ); +$template->assign(array( + 'nb_thumbs_page' => $nb_thumbs_page, + 'nb_thumbs_set' => count($page['cat_elements_id']), + 'CACHE_KEYS' => get_admin_client_cache_keys(array('tags')) + )); trigger_action('loc_end_element_set_global'); diff --git a/admin/batch_manager_unit.php b/admin/batch_manager_unit.php index bbbe4810c..05424dccf 100644 --- a/admin/batch_manager_unit.php +++ b/admin/batch_manager_unit.php @@ -248,7 +248,10 @@ SELECT )); } - $template->assign('ELEMENT_IDS', implode(',', $element_ids)); + $template->assign(array( + 'ELEMENT_IDS' => implode(',', $element_ids), + 'CACHE_KEYS' => get_admin_client_cache_keys(array('tags')), + )); } trigger_action('loc_end_element_set_unit'); diff --git a/admin/cat_perm.php b/admin/cat_perm.php index 71653d9ec..c42b3eaa2 100644 --- a/admin/cat_perm.php +++ b/admin/cat_perm.php @@ -298,7 +298,11 @@ SELECT user_id, group_id // +-----------------------------------------------------------------------+ // | sending html code | // +-----------------------------------------------------------------------+ -$template->assign(array('PWG_TOKEN' => get_pwg_token(), 'INHERIT' => $conf['inheritance_by_default'])); +$template->assign(array( + 'PWG_TOKEN' => get_pwg_token(), + 'INHERIT' => $conf['inheritance_by_default'], + 'CACHE_KEYS' => get_admin_client_cache_keys(array('groups', 'users')), + )); $template->assign_var_from_handle('ADMIN_CONTENT', 'cat_perm'); ?> diff --git a/admin/include/functions.php b/admin/include/functions.php index 384189408..a3778f595 100644 --- a/admin/include/functions.php +++ b/admin/include/functions.php @@ -400,13 +400,8 @@ function delete_orphan_tags() { $orphan_tag_ids[] = $tag['id']; } - - $query = ' -DELETE - FROM '.TAGS_TABLE.' - WHERE id IN ('.implode(',', $orphan_tag_ids).') -;'; - pwg_query($query); + + delete_tags($orphan_tag_ids); } } @@ -2733,4 +2728,54 @@ function deltree($path, $trash_path=null) } } -?>
\ No newline at end of file +/** + * Returns keys to identify the state of main tables. A key consists of the + * last modification timestamp and the total of items (separated by a _). + * Additionally returns the hash of root path. + * Used to invalidate LocalStorage cache on admin pages. + * + * @param string|string[] list of keys to retrieve (categories,groups,images,tags,users) + * @return string[] + */ +function get_admin_client_cache_keys($requested=array()) +{ + $tables = array( + 'categories' => CATEGORIES_TABLE, + 'groups' => GROUPS_TABLE, + 'images' => IMAGES_TABLE, + 'tags' => TAGS_TABLE, + 'users' => USER_INFOS_TABLE + ); + + if (!is_array($requested)) + { + $requested = array($requested); + } + if (empty($requested)) + { + $requested = array_keys($tables); + } + else + { + $requested = array_intersect($requested, array_keys($tables)); + } + + $keys = array( + '_hash' => md5(get_absolute_root_url()), + ); + + foreach ($requested as $item) + { + $query = ' +SELECT CONCAT( + UNIX_TIMESTAMP(MAX(lastmodified)), + "_", + COUNT(*) + ) + FROM '. $tables[$item] .' +;'; + list($keys[$item]) = pwg_db_fetch_row(pwg_query($query)); + } + + return $keys; +}
\ No newline at end of file diff --git a/admin/picture_modify.php b/admin/picture_modify.php index 1b99e5f55..370d64caf 100644 --- a/admin/picture_modify.php +++ b/admin/picture_modify.php @@ -408,7 +408,11 @@ SELECT id ;'; $associate_options_selected = query2array($query, null, 'id'); -$template->assign(compact('associate_options_selected', 'represent_options_selected')); +$template->assign(array( + 'associate_options_selected' => $associate_options_selected, + 'represent_options_selected' => $represent_options_selected, + 'CACHE_KEYS' => get_admin_client_cache_keys(array('tags', 'categories')), + )); trigger_action('loc_end_picture_modify'); diff --git a/admin/themes/default/js/LocalStorageCache.js b/admin/themes/default/js/LocalStorageCache.js index 49a4fa98d..c18171efc 100644 --- a/admin/themes/default/js/LocalStorageCache.js +++ b/admin/themes/default/js/LocalStorageCache.js @@ -1,7 +1,8 @@ -var LocalStorageCache = function(key, lifetime, loader) { - this.key = key; - this.lifetime = lifetime*1000; - this.loader = loader; +var LocalStorageCache = function(options) { + this.key = options.key + '-' + options.serverId; + this.serverKey = options.serverKey; + this.lifetime = options.lifetime ? options.lifetime*1000 : 3600*1000; + this.loader = options.loader; this.storage = window.localStorage; this.ready = !!this.storage; @@ -14,28 +15,23 @@ LocalStorageCache.prototype.get = function(callback) { if (this.ready && this.storage[this.key] != undefined) { var cache = JSON.parse(this.storage[this.key]); - if (now - cache.timestamp <= this.lifetime) { + if (now - cache.timestamp <= this.lifetime && cache.key == this.serverKey) { callback(cache.data); return; } } this.loader(function(data) { - if (that.ready) { - that.storage[that.key] = JSON.stringify({ - timestamp: now, - data: data - }); - } - + that.set.call(that, data); callback(data); }); }; LocalStorageCache.prototype.set = function(data) { if (this.ready) { - that.storage[that.key] = JSON.stringify({ + this.storage[this.key] = JSON.stringify({ timestamp: new Date().getTime(), + key: this.serverKey, data: data }); } diff --git a/admin/themes/default/template/batch_manager_global.tpl b/admin/themes/default/template/batch_manager_global.tpl index 3e22edb02..087f9916a 100644 --- a/admin/themes/default/template/batch_manager_global.tpl +++ b/admin/themes/default/template/batch_manager_global.tpl @@ -68,16 +68,22 @@ jQuery(document).ready(function() {ldelim} jQuery("a.preview-box").colorbox(); {* <!-- TAGS --> *} - var tagsCache = new LocalStorageCache('tagsAdminList', 5*60, function(callback) { - jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.tags.getAdminList', function(data) { - var tags = data.result.tags; - - for (var i=0, l=tags.length; i<l; i++) { - tags[i].id = '~~' + tags[i].id + '~~'; - } - - callback(tags); - }); + var tagsCache = new LocalStorageCache({ + key: 'tagsAdminList', + serverKey: '{$CACHE_KEYS.tags}', + serverId: '{$CACHE_KEYS._hash}', + + loader: function(callback) { + jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.tags.getAdminList', function(data) { + var tags = data.result.tags; + + for (var i=0, l=tags.length; i<l; i++) { + tags[i].id = '~~' + tags[i].id + '~~'; + } + + callback(tags); + }); + } }); jQuery('[data-selectize=tags]').selectize({ @@ -92,14 +98,7 @@ jQuery(document).ready(function() {ldelim} labelField: 'name', searchField: ['name'], plugins: ['remove_button'], - create: function(input, callback) { - tagsCache.clear(); - - callback({ - id: input, - name: input - }); - } + create: true }); tagsCache.get(function(tags) { diff --git a/admin/themes/default/template/batch_manager_unit.tpl b/admin/themes/default/template/batch_manager_unit.tpl index d0d06e11d..6d5a90ddd 100644 --- a/admin/themes/default/template/batch_manager_unit.tpl +++ b/admin/themes/default/template/batch_manager_unit.tpl @@ -10,16 +10,22 @@ {footer_script} (function(){ {* <!-- TAGS --> *} -var tagsCache = new LocalStorageCache('tagsAdminList', 5*60, function(callback) { - jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.tags.getAdminList', function(data) { - var tags = data.result.tags; - - for (var i=0, l=tags.length; i<l; i++) { - tags[i].id = '~~' + tags[i].id + '~~'; - } - - callback(tags); - }); +var tagsCache = new LocalStorageCache({ + key: 'tagsAdminList', + serverKey: '{$CACHE_KEYS.tags}', + serverId: '{$CACHE_KEYS._hash}', + + loader: function(callback) { + jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.tags.getAdminList', function(data) { + var tags = data.result.tags; + + for (var i=0, l=tags.length; i<l; i++) { + tags[i].id = '~~' + tags[i].id + '~~'; + } + + callback(tags); + }); + } }); jQuery('[data-selectize=tags]').selectize({ @@ -27,14 +33,7 @@ jQuery('[data-selectize=tags]').selectize({ labelField: 'name', searchField: ['name'], plugins: ['remove_button'], - create: function(input, callback) { - tagsCache.clear(); - - callback({ - id: input, - name: input - }); - } + create: true }); tagsCache.get(function(tags) { diff --git a/admin/themes/default/template/cat_perm.tpl b/admin/themes/default/template/cat_perm.tpl index ba0813014..d810475b2 100644 --- a/admin/themes/default/template/cat_perm.tpl +++ b/admin/themes/default/template/cat_perm.tpl @@ -6,10 +6,16 @@ {footer_script} (function(){ {* <!-- GROUPS --> *} -var groupsCache = new LocalStorageCache('groupsAdminList', 5*60, function(callback) { - jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.groups.getList&per_page=99999', function(data) { - callback(data.result.groups); - }); +var groupsCache = new LocalStorageCache({ + key: 'groupsAdminList', + serverKey: '{$CACHE_KEYS.groups}', + serverId: '{$CACHE_KEYS._hash}', + + loader: function(callback) { + jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.groups.getList&per_page=99999', function(data) { + callback(data.result.groups); + }); + } }); jQuery('[data-selectize=groups]').selectize({ @@ -32,22 +38,28 @@ groupsCache.get(function(groups) { }); {* <!-- USERS --> *} -var usersCache = new LocalStorageCache('usersAdminList', 5*60, function(callback) { - var page = 0, - users = []; - - (function load(page){ - jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.users.getList&display=username&per_page=99999&page='+ page, function(data) { - users = users.concat(data.result.users); - - if (data.result.paging.count == data.result.paging.per_page) { - load(++page); - } - else { - callback(users); - } - }); - }(page)); +var usersCache = new LocalStorageCache({ + key: 'usersAdminList', + serverKey: '{$CACHE_KEYS.users}', + serverId: '{$CACHE_KEYS._hash}', + + loader: function(callback) { + var users = []; + + // recursive loader + (function load(page){ + jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.users.getList&display=username&per_page=99999&page='+ page, function(data) { + users = users.concat(data.result.users); + + if (data.result.paging.count == data.result.paging.per_page) { + load(++page); + } + else { + callback(users); + } + }); + }(0)); + } }); jQuery('[data-selectize=users]').selectize({ @@ -68,6 +80,29 @@ usersCache.get(function(users) { }, this)); }); }); + +{* <!-- TOGGLES --> *} +function checkStatusOptions() { + if (jQuery("input[name=status]:checked").val() == "private") { + jQuery("#privateOptions, #applytoSubAction").show(); + } + else { + jQuery("#privateOptions, #applytoSubAction").hide(); + } +} + +checkStatusOptions(); +jQuery("#selectStatus").change(function() { + checkStatusOptions(); +}); + +{if isset($nb_users_granted_indirect) && $nb_users_granted_indirect>0} + jQuery(".toggle-indirectPermissions").click(function(e){ + jQuery(".toggle-indirectPermissions").toggle(); + jQuery("#indirectPermissionsDetails").toggle(); + e.preventDefault(); + }); +{/if} }()); {/footer_script} @@ -111,8 +146,8 @@ usersCache.get(function(users) { {if isset($nb_users_granted_indirect) && $nb_users_granted_indirect>0} <p> {'%u users have automatic permission because they belong to a granted group.'|@translate:$nb_users_granted_indirect} - <a href="#" id="indirectPermissionsDetailsHide" style="display:none">{'hide details'|@translate}</a> - <a href="#" id="indirectPermissionsDetailsShow">{'show details'|@translate}</a> + <a href="#" class="toggle-indirectPermissions" style="display:none">{'hide details'|@translate}</a> + <a href="#" class="toggle-indirectPermissions">{'show details'|@translate}</a> <ul id="indirectPermissionsDetails" style="display:none"> {foreach from=$user_granted_indirect_groups item=group_details} @@ -184,7 +219,10 @@ usersCache.get(function(users) { <p style="margin:12px;text-align:left;"> <input class="submit" type="submit" value="{'Save Settings'|@translate}" name="submit"> - <label id="applytoSubAction" style="display:none;"><input type="checkbox" name="apply_on_sub" {if $INHERIT}checked="checked"{/if}>{'Apply to sub-albums'|@translate}</label> + <label id="applytoSubAction" style="display:none;"> + <input type="checkbox" name="apply_on_sub" {if $INHERIT}checked="checked"{/if}> + {'Apply to sub-albums'|@translate} + </label> </p> <input type="hidden" name="pwg_token" value="{$PWG_TOKEN}"> diff --git a/admin/themes/default/template/picture_modify.tpl b/admin/themes/default/template/picture_modify.tpl index f48a152d6..602b9b126 100644 --- a/admin/themes/default/template/picture_modify.tpl +++ b/admin/themes/default/template/picture_modify.tpl @@ -10,10 +10,16 @@ {footer_script} (function(){ {* <!-- CATEGORIES --> *} -var categoriesCache = new LocalStorageCache('categoriesAdminList', 5*60, function(callback) { - jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.categories.getAdminList', function(data) { - callback(data.result.categories); - }); +var categoriesCache = new LocalStorageCache({ + key: 'categoriesAdminList', + serverKey: '{$CACHE_KEYS.categories}', + serverId: '{$CACHE_KEYS._hash}', + + loader: function(callback) { + jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.categories.getAdminList', function(data) { + callback(data.result.categories); + }); + } }); jQuery('[data-selectize=categories]').selectize({ @@ -36,16 +42,22 @@ categoriesCache.get(function(categories) { }); {* <!-- TAGS --> *} -var tagsCache = new LocalStorageCache('tagsAdminList', 5*60, function(callback) { - jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.tags.getAdminList', function(data) { - var tags = data.result.tags; - - for (var i=0, l=tags.length; i<l; i++) { - tags[i].id = '~~' + tags[i].id + '~~'; - } - - callback(tags); - }); +var tagsCache = new LocalStorageCache({ + key: 'tagsAdminList', + serverKey: '{$CACHE_KEYS.tags}', + serverId: '{$CACHE_KEYS._hash}', + + loader: function(callback) { + jQuery.getJSON('{$ROOT_URL}ws.php?format=json&method=pwg.tags.getAdminList', function(data) { + var tags = data.result.tags; + + for (var i=0, l=tags.length; i<l; i++) { + tags[i].id = '~~' + tags[i].id + '~~'; + } + + callback(tags); + }); + } }); jQuery('[data-selectize=tags]').selectize({ @@ -53,14 +65,7 @@ jQuery('[data-selectize=tags]').selectize({ labelField: 'name', searchField: ['name'], plugins: ['remove_button'], - create: function(input, callback) { - tagsCache.clear(); - - callback({ - id: input, - name: input - }); - } + create: true }); tagsCache.get(function(tags) { diff --git a/install/db/141-database.php b/install/db/141-database.php new file mode 100644 index 000000000..f6a157123 --- /dev/null +++ b/install/db/141-database.php @@ -0,0 +1,45 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based photo gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008-2014 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +defined('PHPWG_ROOT_PATH') or die('Hacking attempt!'); + +$upgrade_description = 'add lastmodified field for categories, images, groups, users, tags'; + +$tables = array( + CATEGORIES_TABLE, + GROUPS_TABLE, + IMAGES_TABLE, + TAGS_TABLE, + USER_INFOS_TABLE + ); + +foreach ($tables as $table) +{ + pwg_query(' +ALTER TABLE '. $table .' + ADD `lastmodified` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + ADD INDEX `lastmodified` (`lastmodified`) +;'); +} + +echo "\n".$upgrade_description."\n"; diff --git a/install/piwigo_structure-mysql.sql b/install/piwigo_structure-mysql.sql index 7520d99a4..c05dcb981 100644 --- a/install/piwigo_structure-mysql.sql +++ b/install/piwigo_structure-mysql.sql @@ -36,9 +36,11 @@ CREATE TABLE `piwigo_categories` ( `global_rank` varchar(255) default NULL, `image_order` varchar(128) default NULL, `permalink` varchar(64) binary default NULL, + `lastmodified` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `categories_i3` (`permalink`), - KEY `categories_i2` (`id_uppercat`) + KEY `categories_i2` (`id_uppercat`), + KEY `lastmodified` (`lastmodified`) ) ENGINE=MyISAM; -- @@ -106,8 +108,10 @@ CREATE TABLE `piwigo_groups` ( `id` smallint(5) unsigned NOT NULL auto_increment, `name` varchar(255) NOT NULL default '', `is_default` enum('true','false') NOT NULL default 'false', + `lastmodified` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), - UNIQUE KEY `groups_ui1` (`name`) + UNIQUE KEY `groups_ui1` (`name`), + KEY `lastmodified` (`lastmodified`) ) ENGINE=MyISAM; -- @@ -199,13 +203,15 @@ CREATE TABLE `piwigo_images` ( `rotation` tinyint unsigned default NULL, `latitude` double(8, 6) default NULL, `longitude` double(9, 6) default NULL, + `lastmodified` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `images_i2` (`date_available`), KEY `images_i3` (`rating_score`), KEY `images_i4` (`hit`), KEY `images_i5` (`date_creation`), KEY `images_i1` (`storage_category_id`), - KEY `images_i6` (`latitude`) + KEY `images_i6` (`latitude`), + KEY `lastmodified` (`lastmodified`) ) ENGINE=MyISAM; -- @@ -305,8 +311,10 @@ CREATE TABLE `piwigo_tags` ( `id` smallint(5) unsigned NOT NULL auto_increment, `name` varchar(255) NOT NULL default '', `url_name` varchar(255) binary NOT NULL default '', + `lastmodified` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), - KEY `tags_i1` (`url_name`) + KEY `tags_i1` (`url_name`), + KEY `lastmodified` (`lastmodified`) ) ENGINE=MyISAM; -- @@ -423,7 +431,9 @@ CREATE TABLE `piwigo_user_infos` ( `enabled_high` enum('true','false') NOT NULL default 'true', `level` tinyint unsigned NOT NULL default '0', `activation_key` char(20) default NULL, - PRIMARY KEY (`user_id`) + `lastmodified` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`), + KEY `lastmodified` (`lastmodified`) ) ENGINE=MyISAM; -- |