mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	* feat: #8824, cache refactor ability to disable caches ability to download contents of cache refactor cache modules to remove duplicated code * fix: remove duplicate hit/miss tracking check cacheEnabled in getUncachedKeys
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							bcbc085497
						
					
				
				
					commit
					f1f9b225b0
				
			| @@ -1,11 +1,11 @@ | |||||||
| { | { | ||||||
| 	"post-cache": "Post Cache", | 	"post-cache": "Post Cache", | ||||||
| 	"posts-in-cache": "Posts in Cache", |  | ||||||
| 	"average-post-size": "Average Post Size", |  | ||||||
| 	"length-to-max": "Length / Max", |  | ||||||
| 	"percent-full": "%1% Full", | 	"percent-full": "%1% Full", | ||||||
| 	"post-cache-size": "Post Cache Size", | 	"post-cache-size": "Post Cache Size", | ||||||
| 	"items-in-cache": "Items in Cache", | 	"items-in-cache": "Items in Cache", | ||||||
| 	"control-panel": "Control Panel", | 	"control-panel": "Control Panel", | ||||||
| 	"update-settings": "Update Cache Settings" | 	"update-settings": "Update Cache Settings", | ||||||
|  | 	"clear": "Clear", | ||||||
|  | 	"download": "Download", | ||||||
|  | 	"enabled": "Enabled" | ||||||
| } | } | ||||||
| @@ -23,14 +23,14 @@ get: | |||||||
|                         type: number |                         type: number | ||||||
|                       percentFull: |                       percentFull: | ||||||
|                         type: number |                         type: number | ||||||
|                       avgPostSize: |  | ||||||
|                         type: number |  | ||||||
|                       hits: |                       hits: | ||||||
|                         type: string |                         type: string | ||||||
|                       misses: |                       misses: | ||||||
|                         type: string |                         type: string | ||||||
|                       hitRatio: |                       hitRatio: | ||||||
|                         type: string |                         type: string | ||||||
|  |                       enabled: | ||||||
|  |                         type: boolean | ||||||
|                   groupCache: |                   groupCache: | ||||||
|                     type: object |                     type: object | ||||||
|                     properties: |                     properties: | ||||||
| @@ -48,6 +48,8 @@ get: | |||||||
|                         type: string |                         type: string | ||||||
|                       hitRatio: |                       hitRatio: | ||||||
|                         type: string |                         type: string | ||||||
|  |                       enabled: | ||||||
|  |                         type: boolean | ||||||
|                   localCache: |                   localCache: | ||||||
|                     type: object |                     type: object | ||||||
|                     properties: |                     properties: | ||||||
| @@ -59,14 +61,14 @@ get: | |||||||
|                         type: number |                         type: number | ||||||
|                       percentFull: |                       percentFull: | ||||||
|                         type: number |                         type: number | ||||||
|                       dump: |  | ||||||
|                         type: boolean |  | ||||||
|                       hits: |                       hits: | ||||||
|                         type: string |                         type: string | ||||||
|                       misses: |                       misses: | ||||||
|                         type: string |                         type: string | ||||||
|                       hitRatio: |                       hitRatio: | ||||||
|                         type: string |                         type: string | ||||||
|  |                       enabled: | ||||||
|  |                         type: boolean | ||||||
|                   objectCache: |                   objectCache: | ||||||
|                     type: object |                     type: object | ||||||
|                     properties: |                     properties: | ||||||
| @@ -84,6 +86,8 @@ get: | |||||||
|                         type: string |                         type: string | ||||||
|                       hitRatio: |                       hitRatio: | ||||||
|                         type: string |                         type: string | ||||||
|  |                       enabled: | ||||||
|  |                         type: boolean | ||||||
|                 required: |                 required: | ||||||
|                   - postCache |                   - postCache | ||||||
|                   - groupCache |                   - groupCache | ||||||
|   | |||||||
| @@ -15,6 +15,16 @@ define('admin/advanced/cache', function () { | |||||||
| 				ajaxify.refresh(); | 				ajaxify.refresh(); | ||||||
| 			}); | 			}); | ||||||
| 		}); | 		}); | ||||||
|  | 		$('.checkbox').on('change', function () { | ||||||
|  | 			var input = $(this).find('input'); | ||||||
|  | 			var flag = input.is(':checked'); | ||||||
|  | 			var name = $(this).attr('data-name'); | ||||||
|  | 			socket.emit('admin.cache.toggle', { name: name, enabled: flag }, function (err) { | ||||||
|  | 				if (err) { | ||||||
|  | 					return app.alertError(err.message); | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
| 	}; | 	}; | ||||||
| 	return Cache; | 	return Cache; | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										53
									
								
								src/cache.js
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								src/cache.js
									
									
									
									
									
								
							| @@ -1,56 +1,9 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| const LRU = require('lru-cache'); | const cacheCreate = require('./cacheCreate'); | ||||||
| const pubsub = require('./pubsub'); |  | ||||||
|  |  | ||||||
| const cache = new LRU({ | module.exports = cacheCreate({ | ||||||
|  | 	name: 'local', | ||||||
| 	max: 4000, | 	max: 4000, | ||||||
| 	maxAge: 0, | 	maxAge: 0, | ||||||
| }); | }); | ||||||
| cache.hits = 0; |  | ||||||
| cache.misses = 0; |  | ||||||
|  |  | ||||||
| const cacheGet = cache.get; |  | ||||||
| const cacheDel = cache.del; |  | ||||||
| const cacheReset = cache.reset; |  | ||||||
|  |  | ||||||
| cache.get = function (key) { |  | ||||||
| 	const data = cacheGet.apply(cache, [key]); |  | ||||||
| 	if (data === undefined) { |  | ||||||
| 		cache.misses += 1; |  | ||||||
| 	} else { |  | ||||||
| 		cache.hits += 1; |  | ||||||
| 	} |  | ||||||
| 	return data; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| cache.del = function (key) { |  | ||||||
| 	if (!Array.isArray(key)) { |  | ||||||
| 		key = [key]; |  | ||||||
| 	} |  | ||||||
| 	pubsub.publish('local:cache:del', key); |  | ||||||
| 	key.forEach(key => cacheDel.apply(cache, [key])); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| cache.reset = function () { |  | ||||||
| 	pubsub.publish('local:cache:reset'); |  | ||||||
| 	localReset(); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| function localReset() { |  | ||||||
| 	cacheReset.apply(cache); |  | ||||||
| 	cache.hits = 0; |  | ||||||
| 	cache.misses = 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pubsub.on('local:cache:reset', function () { |  | ||||||
| 	localReset(); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| pubsub.on('local:cache:del', function (keys) { |  | ||||||
| 	if (Array.isArray(keys)) { |  | ||||||
| 		keys.forEach(key => cacheDel.apply(cache, [key])); |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| module.exports = cache; |  | ||||||
|   | |||||||
							
								
								
									
										91
									
								
								src/cacheCreate.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/cacheCreate.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | module.exports = function (opts) { | ||||||
|  | 	const LRU = require('lru-cache'); | ||||||
|  | 	const pubsub = require('./pubsub'); | ||||||
|  |  | ||||||
|  | 	const cache = new LRU(opts); | ||||||
|  |  | ||||||
|  | 	cache.name = opts.name; | ||||||
|  | 	cache.hits = 0; | ||||||
|  | 	cache.misses = 0; | ||||||
|  | 	cache.enabled = opts.hasOwnProperty('enabled') ? opts.enabled : true; | ||||||
|  |  | ||||||
|  | 	const cacheSet = cache.set; | ||||||
|  | 	const cacheGet = cache.get; | ||||||
|  | 	const cacheDel = cache.del; | ||||||
|  | 	const cacheReset = cache.reset; | ||||||
|  |  | ||||||
|  | 	cache.set = function (key, value) { | ||||||
|  | 		if (!cache.enabled) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		cacheSet.apply(cache, [key, value]); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	cache.get = function (key) { | ||||||
|  | 		if (!cache.enabled) { | ||||||
|  | 			return undefined; | ||||||
|  | 		} | ||||||
|  | 		const data = cacheGet.apply(cache, [key]); | ||||||
|  | 		if (data === undefined) { | ||||||
|  | 			cache.misses += 1; | ||||||
|  | 		} else { | ||||||
|  | 			cache.hits += 1; | ||||||
|  | 		} | ||||||
|  | 		return data; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	cache.del = function (keys) { | ||||||
|  | 		if (!Array.isArray(keys)) { | ||||||
|  | 			keys = [keys]; | ||||||
|  | 		} | ||||||
|  | 		pubsub.publish(cache.name + ':cache:del', keys); | ||||||
|  | 		keys.forEach(key => cacheDel.apply(cache, [key])); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	cache.reset = function () { | ||||||
|  | 		pubsub.publish(cache.name + ':cache:reset'); | ||||||
|  | 		localReset(); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	function localReset() { | ||||||
|  | 		cacheReset.apply(cache); | ||||||
|  | 		cache.hits = 0; | ||||||
|  | 		cache.misses = 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pubsub.on(cache.name + ':cache:reset', function () { | ||||||
|  | 		localReset(); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	pubsub.on(cache.name + ':cache:del', function (keys) { | ||||||
|  | 		if (Array.isArray(keys)) { | ||||||
|  | 			keys.forEach(key => cacheDel.apply(cache, [key])); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	cache.getUnCachedKeys = function (keys, cachedData) { | ||||||
|  | 		if (!cache.enabled) { | ||||||
|  | 			return keys; | ||||||
|  | 		} | ||||||
|  | 		let data; | ||||||
|  | 		let isCached; | ||||||
|  | 		const unCachedKeys = keys.filter(function (key) { | ||||||
|  | 			data = cache.get(key); | ||||||
|  | 			isCached = data !== undefined; | ||||||
|  | 			if (isCached) { | ||||||
|  | 				cachedData[key] = data; | ||||||
|  | 			} | ||||||
|  | 			return !isCached; | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		var hits = keys.length - unCachedKeys.length; | ||||||
|  | 		var misses = keys.length - hits; | ||||||
|  | 		cache.hits += hits; | ||||||
|  | 		cache.misses += misses; | ||||||
|  | 		return unCachedKeys; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	return cache; | ||||||
|  | }; | ||||||
| @@ -10,10 +10,8 @@ cacheController.get = function (req, res) { | |||||||
| 	const objectCache = require('../../database').objectCache; | 	const objectCache = require('../../database').objectCache; | ||||||
| 	const localCache = require('../../cache'); | 	const localCache = require('../../cache'); | ||||||
|  |  | ||||||
| 	let avgPostSize = 0; |  | ||||||
| 	let percentFull = 0; | 	let percentFull = 0; | ||||||
| 	if (postCache.itemCount > 0) { | 	if (postCache.itemCount > 0) { | ||||||
| 		avgPostSize = parseInt((postCache.length / postCache.itemCount), 10); |  | ||||||
| 		percentFull = ((postCache.length / postCache.max) * 100).toFixed(2); | 		percentFull = ((postCache.length / postCache.max) * 100).toFixed(2); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -23,10 +21,10 @@ cacheController.get = function (req, res) { | |||||||
| 			max: postCache.max, | 			max: postCache.max, | ||||||
| 			itemCount: postCache.itemCount, | 			itemCount: postCache.itemCount, | ||||||
| 			percentFull: percentFull, | 			percentFull: percentFull, | ||||||
| 			avgPostSize: avgPostSize, |  | ||||||
| 			hits: utils.addCommas(String(postCache.hits)), | 			hits: utils.addCommas(String(postCache.hits)), | ||||||
| 			misses: utils.addCommas(String(postCache.misses)), | 			misses: utils.addCommas(String(postCache.misses)), | ||||||
| 			hitRatio: ((postCache.hits / (postCache.hits + postCache.misses) || 0)).toFixed(4), | 			hitRatio: ((postCache.hits / (postCache.hits + postCache.misses) || 0)).toFixed(4), | ||||||
|  | 			enabled: postCache.enabled, | ||||||
| 		}, | 		}, | ||||||
| 		groupCache: { | 		groupCache: { | ||||||
| 			length: groupCache.length, | 			length: groupCache.length, | ||||||
| @@ -36,16 +34,17 @@ cacheController.get = function (req, res) { | |||||||
| 			hits: utils.addCommas(String(groupCache.hits)), | 			hits: utils.addCommas(String(groupCache.hits)), | ||||||
| 			misses: utils.addCommas(String(groupCache.misses)), | 			misses: utils.addCommas(String(groupCache.misses)), | ||||||
| 			hitRatio: (groupCache.hits / (groupCache.hits + groupCache.misses)).toFixed(4), | 			hitRatio: (groupCache.hits / (groupCache.hits + groupCache.misses)).toFixed(4), | ||||||
|  | 			enabled: groupCache.enabled, | ||||||
| 		}, | 		}, | ||||||
| 		localCache: { | 		localCache: { | ||||||
| 			length: localCache.length, | 			length: localCache.length, | ||||||
| 			max: localCache.max, | 			max: localCache.max, | ||||||
| 			itemCount: localCache.itemCount, | 			itemCount: localCache.itemCount, | ||||||
| 			percentFull: ((localCache.length / localCache.max) * 100).toFixed(2), | 			percentFull: ((localCache.length / localCache.max) * 100).toFixed(2), | ||||||
| 			dump: req.query.debug ? JSON.stringify(localCache.dump(), null, 4) : false, |  | ||||||
| 			hits: utils.addCommas(String(localCache.hits)), | 			hits: utils.addCommas(String(localCache.hits)), | ||||||
| 			misses: utils.addCommas(String(localCache.misses)), | 			misses: utils.addCommas(String(localCache.misses)), | ||||||
| 			hitRatio: ((localCache.hits / (localCache.hits + localCache.misses) || 0)).toFixed(4), | 			hitRatio: ((localCache.hits / (localCache.hits + localCache.misses) || 0)).toFixed(4), | ||||||
|  | 			enabled: localCache.enabled, | ||||||
| 		}, | 		}, | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -58,8 +57,31 @@ cacheController.get = function (req, res) { | |||||||
| 			hits: utils.addCommas(String(objectCache.hits)), | 			hits: utils.addCommas(String(objectCache.hits)), | ||||||
| 			misses: utils.addCommas(String(objectCache.misses)), | 			misses: utils.addCommas(String(objectCache.misses)), | ||||||
| 			hitRatio: (objectCache.hits / (objectCache.hits + objectCache.misses)).toFixed(4), | 			hitRatio: (objectCache.hits / (objectCache.hits + objectCache.misses)).toFixed(4), | ||||||
|  | 			enabled: objectCache.enabled, | ||||||
| 		}; | 		}; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	res.render('admin/advanced/cache', data); | 	res.render('admin/advanced/cache', data); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | cacheController.dump = function (req, res, next) { | ||||||
|  | 	const caches = { | ||||||
|  | 		post: require('../../posts/cache'), | ||||||
|  | 		object: require('../../database').objectCache, | ||||||
|  | 		group: require('../../groups').cache, | ||||||
|  | 		local: require('../../cache'), | ||||||
|  | 	}; | ||||||
|  | 	if (!caches[req.query.name]) { | ||||||
|  | 		return next(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const data = JSON.stringify(caches[req.query.name].dump(), null, 4); | ||||||
|  | 	res.setHeader('Content-disposition', 'attachment; filename= ' + req.query.name + '-cache.json'); | ||||||
|  | 	res.setHeader('Content-type', 'application/json'); | ||||||
|  | 	res.write(data, function (err) { | ||||||
|  | 		if (err) { | ||||||
|  | 			return next(err); | ||||||
|  | 		} | ||||||
|  | 		res.end(); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|   | |||||||
| @@ -1,56 +1,11 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| module.exports.create = function (name) { | module.exports.create = function (name) { | ||||||
| 	var LRU = require('lru-cache'); | 	const cacheCreate = require('../cacheCreate'); | ||||||
| 	var pubsub = require('../pubsub'); | 	return cacheCreate({ | ||||||
|  | 		name: name + '-object', | ||||||
| 	var cache = new LRU({ |  | ||||||
| 		max: 40000, | 		max: 40000, | ||||||
| 		length: function () { return 1; }, | 		length: function () { return 1; }, | ||||||
| 		maxAge: 0, | 		maxAge: 0, | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
| 	cache.misses = 0; |  | ||||||
| 	cache.hits = 0; |  | ||||||
|  |  | ||||||
| 	pubsub.on(name + ':hash:cache:del', function (keys) { |  | ||||||
| 		keys.forEach(key => cache.del(key)); |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	pubsub.on(name + ':hash:cache:reset', function () { |  | ||||||
| 		cache.reset(); |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	cache.delObjectCache = function (keys) { |  | ||||||
| 		if (!Array.isArray(keys)) { |  | ||||||
| 			keys = [keys]; |  | ||||||
| 		} |  | ||||||
| 		pubsub.publish(name + ':hash:cache:del', keys); |  | ||||||
| 		keys.forEach(key => cache.del(key)); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	cache.resetObjectCache = function () { |  | ||||||
| 		pubsub.publish(name + ':hash:cache:reset'); |  | ||||||
| 		cache.reset(); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	cache.getUnCachedKeys = function (keys, cachedData) { |  | ||||||
| 		let data; |  | ||||||
| 		let isCached; |  | ||||||
| 		const unCachedKeys = keys.filter(function (key) { |  | ||||||
| 			data = cache.get(key); |  | ||||||
| 			isCached = data !== undefined; |  | ||||||
| 			if (isCached) { |  | ||||||
| 				cachedData[key] = data; |  | ||||||
| 			} |  | ||||||
| 			return !isCached; |  | ||||||
| 		}); |  | ||||||
|  |  | ||||||
| 		var hits = keys.length - unCachedKeys.length; |  | ||||||
| 		var misses = keys.length - hits; |  | ||||||
| 		cache.hits += hits; |  | ||||||
| 		cache.misses += misses; |  | ||||||
| 		return unCachedKeys; |  | ||||||
| 	}; |  | ||||||
| 	return cache; |  | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ module.exports = function (module) { | |||||||
| 			throw err; | 			throw err; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.setObjectField = async function (key, field, value) { | 	module.setObjectField = async function (key, field, value) { | ||||||
| @@ -164,7 +164,7 @@ module.exports = function (module) { | |||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
| 		await module.client.collection('objects').updateOne({ _key: key }, { $unset: data }); | 		await module.client.collection('objects').updateOne({ _key: key }, { $unset: data }); | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.incrObjectField = async function (key, field) { | 	module.incrObjectField = async function (key, field) { | ||||||
| @@ -191,13 +191,13 @@ module.exports = function (module) { | |||||||
| 				bulk.find({ _key: key }).upsert().update({ $inc: increment }); | 				bulk.find({ _key: key }).upsert().update({ $inc: increment }); | ||||||
| 			}); | 			}); | ||||||
| 			await bulk.execute(); | 			await bulk.execute(); | ||||||
| 			cache.delObjectCache(key); | 			cache.del(key); | ||||||
| 			const result = await module.getObjectsFields(key, [field]); | 			const result = await module.getObjectsFields(key, [field]); | ||||||
| 			return result.map(data => data && data[field]); | 			return result.map(data => data && data[field]); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		const result = await module.client.collection('objects').findOneAndUpdate({ _key: key }, { $inc: increment }, { returnOriginal: false, upsert: true }); | 		const result = await module.client.collection('objects').findOneAndUpdate({ _key: key }, { $inc: increment }, { returnOriginal: false, upsert: true }); | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 		return result && result.value ? result.value[field] : null; | 		return result && result.value ? result.value[field] : null; | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ module.exports = function (module) { | |||||||
|  |  | ||||||
| 	module.emptydb = async function () { | 	module.emptydb = async function () { | ||||||
| 		await module.client.collection('objects').deleteMany({}); | 		await module.client.collection('objects').deleteMany({}); | ||||||
| 		module.objectCache.resetObjectCache(); | 		module.objectCache.reset(); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.exists = async function (key) { | 	module.exists = async function (key) { | ||||||
| @@ -47,7 +47,7 @@ module.exports = function (module) { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		await module.client.collection('objects').deleteMany({ _key: key }); | 		await module.client.collection('objects').deleteMany({ _key: key }); | ||||||
| 		module.objectCache.delObjectCache(key); | 		module.objectCache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.deleteAll = async function (keys) { | 	module.deleteAll = async function (keys) { | ||||||
| @@ -55,7 +55,7 @@ module.exports = function (module) { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		await module.client.collection('objects').deleteMany({ _key: { $in: keys } }); | 		await module.client.collection('objects').deleteMany({ _key: { $in: keys } }); | ||||||
| 		module.objectCache.delObjectCache(keys); | 		module.objectCache.del(keys); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.get = async function (key) { | 	module.get = async function (key) { | ||||||
| @@ -96,7 +96,7 @@ module.exports = function (module) { | |||||||
|  |  | ||||||
| 	module.rename = async function (oldKey, newKey) { | 	module.rename = async function (oldKey, newKey) { | ||||||
| 		await module.client.collection('objects').updateMany({ _key: oldKey }, { $set: { _key: newKey } }); | 		await module.client.collection('objects').updateMany({ _key: oldKey }, { $set: { _key: newKey } }); | ||||||
| 		module.objectCache.delObjectCache([oldKey, newKey]); | 		module.objectCache.del([oldKey, newKey]); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.type = async function (key) { | 	module.type = async function (key) { | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ module.exports = function (module) { | |||||||
| 			await module.client.async.hmset(key, data); | 			await module.client.async.hmset(key, data); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.setObjectField = async function (key, field, value) { | 	module.setObjectField = async function (key, field, value) { | ||||||
| @@ -48,7 +48,7 @@ module.exports = function (module) { | |||||||
| 			await module.client.async.hset(key, field, value); | 			await module.client.async.hset(key, field, value); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.getObject = async function (key) { | 	module.getObject = async function (key) { | ||||||
| @@ -146,7 +146,7 @@ module.exports = function (module) { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		await module.client.async.hdel(key, field); | 		await module.client.async.hdel(key, field); | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.deleteObjectFields = async function (key, fields) { | 	module.deleteObjectFields = async function (key, fields) { | ||||||
| @@ -158,7 +158,7 @@ module.exports = function (module) { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		await module.client.async.hdel(key, fields); | 		await module.client.async.hdel(key, fields); | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.incrObjectField = async function (key, field) { | 	module.incrObjectField = async function (key, field) { | ||||||
| @@ -182,7 +182,7 @@ module.exports = function (module) { | |||||||
| 		} else { | 		} else { | ||||||
| 			result = await module.client.async.hincrby(key, field, value); | 			result = await module.client.async.hincrby(key, field, value); | ||||||
| 		} | 		} | ||||||
| 		cache.delObjectCache(key); | 		cache.del(key); | ||||||
| 		return Array.isArray(result) ? result.map(value => parseInt(value, 10)) : parseInt(result, 10); | 		return Array.isArray(result) ? result.map(value => parseInt(value, 10)) : parseInt(result, 10); | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ module.exports = function (module) { | |||||||
|  |  | ||||||
| 	module.emptydb = async function () { | 	module.emptydb = async function () { | ||||||
| 		await module.flushdb(); | 		await module.flushdb(); | ||||||
| 		module.objectCache.resetObjectCache(); | 		module.objectCache.reset(); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.exists = async function (key) { | 	module.exists = async function (key) { | ||||||
| @@ -45,7 +45,7 @@ module.exports = function (module) { | |||||||
|  |  | ||||||
| 	module.delete = async function (key) { | 	module.delete = async function (key) { | ||||||
| 		await module.client.async.del(key); | 		await module.client.async.del(key); | ||||||
| 		module.objectCache.delObjectCache(key); | 		module.objectCache.del(key); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.deleteAll = async function (keys) { | 	module.deleteAll = async function (keys) { | ||||||
| @@ -53,7 +53,7 @@ module.exports = function (module) { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		await module.client.async.del(keys); | 		await module.client.async.del(keys); | ||||||
| 		module.objectCache.delObjectCache(keys); | 		module.objectCache.del(keys); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.get = async function (key) { | 	module.get = async function (key) { | ||||||
| @@ -77,7 +77,7 @@ module.exports = function (module) { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		module.objectCache.delObjectCache([oldKey, newKey]); | 		module.objectCache.del([oldKey, newKey]); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	module.type = async function (key) { | 	module.type = async function (key) { | ||||||
|   | |||||||
| @@ -1,48 +1,19 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| var LRU = require('lru-cache'); | const cacheCreate = require('../cacheCreate'); | ||||||
| var pubsub = require('../pubsub'); |  | ||||||
|  |  | ||||||
| var cache = new LRU({ |  | ||||||
| 	max: 40000, |  | ||||||
| 	maxAge: 0, |  | ||||||
| }); |  | ||||||
| cache.hits = 0; |  | ||||||
| cache.misses = 0; |  | ||||||
|  |  | ||||||
| module.exports = function (Groups) { | module.exports = function (Groups) { | ||||||
| 	Groups.cache = cache; | 	Groups.cache = cacheCreate({ | ||||||
|  | 		name: 'group', | ||||||
| 	pubsub.on('group:cache:reset', function () { | 		max: 40000, | ||||||
| 		localReset(); | 		maxAge: 0, | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
| 	pubsub.on('group:cache:del', function (data) { |  | ||||||
| 		if (data && data.groupNames) { |  | ||||||
| 			data.groupNames.forEach(function (groupName) { |  | ||||||
| 				cache.del(data.uid + ':' + groupName); |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	Groups.resetCache = function () { |  | ||||||
| 		pubsub.publish('group:cache:reset'); |  | ||||||
| 		localReset(); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	function localReset() { |  | ||||||
| 		cache.reset(); |  | ||||||
| 		cache.hits = 0; |  | ||||||
| 		cache.misses = 0; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	Groups.clearCache = function (uid, groupNames) { | 	Groups.clearCache = function (uid, groupNames) { | ||||||
| 		if (!Array.isArray(groupNames)) { | 		if (!Array.isArray(groupNames)) { | ||||||
| 			groupNames = [groupNames]; | 			groupNames = [groupNames]; | ||||||
| 		} | 		} | ||||||
| 		pubsub.publish('group:cache:del', { uid: uid, groupNames: groupNames }); | 		const keys = groupNames.map(name => uid + ':' + name); | ||||||
| 		groupNames.forEach(function (groupName) { | 		Groups.cache.del(keys); | ||||||
| 			cache.del(uid + ':' + groupName); |  | ||||||
| 		}); |  | ||||||
| 	}; | 	}; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ module.exports = function (Groups) { | |||||||
| 			db.deleteObjectFields('groupslug:groupname', fields), | 			db.deleteObjectFields('groupslug:groupname', fields), | ||||||
| 			removeGroupsFromPrivilegeGroups(groupNames), | 			removeGroupsFromPrivilegeGroups(groupNames), | ||||||
| 		]); | 		]); | ||||||
| 		Groups.resetCache(); | 		Groups.cache.reset(); | ||||||
| 		plugins.fireHook('action:groups.destroy', { groups: groupsData }); | 		plugins.fireHook('action:groups.destroy', { groups: groupsData }); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -31,10 +31,8 @@ module.exports = function (Groups) { | |||||||
| 		const cacheKey = uid + ':' + groupName; | 		const cacheKey = uid + ':' + groupName; | ||||||
| 		let isMember = Groups.cache.get(cacheKey); | 		let isMember = Groups.cache.get(cacheKey); | ||||||
| 		if (isMember !== undefined) { | 		if (isMember !== undefined) { | ||||||
| 			Groups.cache.hits += 1; |  | ||||||
| 			return isMember; | 			return isMember; | ||||||
| 		} | 		} | ||||||
| 		Groups.cache.misses += 1; |  | ||||||
| 		isMember = await db.isSortedSetMember('group:' + groupName + ':members', uid); | 		isMember = await db.isSortedSetMember('group:' + groupName + ':members', uid); | ||||||
| 		Groups.cache.set(cacheKey, isMember); | 		Groups.cache.set(cacheKey, isMember); | ||||||
| 		return isMember; | 		return isMember; | ||||||
| @@ -88,10 +86,7 @@ module.exports = function (Groups) { | |||||||
| 		const isMember = Groups.cache.get(uid + ':' + groupName); | 		const isMember = Groups.cache.get(uid + ':' + groupName); | ||||||
| 		const isInCache = isMember !== undefined; | 		const isInCache = isMember !== undefined; | ||||||
| 		if (isInCache) { | 		if (isInCache) { | ||||||
| 			Groups.cache.hits += 1; |  | ||||||
| 			cachedData[uid + ':' + groupName] = isMember; | 			cachedData[uid + ':' + groupName] = isMember; | ||||||
| 		} else { |  | ||||||
| 			Groups.cache.misses += 1; |  | ||||||
| 		} | 		} | ||||||
| 		return !isInCache; | 		return !isInCache; | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -197,7 +197,7 @@ module.exports = function (Groups) { | |||||||
| 			old: oldName, | 			old: oldName, | ||||||
| 			new: newName, | 			new: newName, | ||||||
| 		}); | 		}); | ||||||
| 		Groups.resetCache(); | 		Groups.cache.reset(); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	async function updateMemberGroupTitles(oldName, newName) { | 	async function updateMemberGroupTitles(oldName, newName) { | ||||||
|   | |||||||
| @@ -1,14 +1,12 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| var LRU = require('lru-cache'); | const cacheCreate = require('../cacheCreate'); | ||||||
| var meta = require('../meta'); | const meta = require('../meta'); | ||||||
|  |  | ||||||
| var cache = new LRU({ | module.exports = cacheCreate({ | ||||||
|  | 	name: 'post', | ||||||
| 	max: meta.config.postCacheSize, | 	max: meta.config.postCacheSize, | ||||||
| 	length: function (n) { return n.length; }, | 	length: function (n) { return n.length; }, | ||||||
| 	maxAge: 0, | 	maxAge: 0, | ||||||
|  | 	enabled: global.env === 'production', | ||||||
| }); | }); | ||||||
| cache.hits = 0; |  | ||||||
| cache.misses = 0; |  | ||||||
|  |  | ||||||
| module.exports = cache; |  | ||||||
|   | |||||||
| @@ -57,13 +57,12 @@ module.exports = function (Posts) { | |||||||
| 		const cachedContent = cache.get(pid); | 		const cachedContent = cache.get(pid); | ||||||
| 		if (postData.pid && cachedContent !== undefined) { | 		if (postData.pid && cachedContent !== undefined) { | ||||||
| 			postData.content = cachedContent; | 			postData.content = cachedContent; | ||||||
| 			cache.hits += 1; |  | ||||||
| 			return postData; | 			return postData; | ||||||
| 		} | 		} | ||||||
| 		cache.misses += 1; |  | ||||||
| 		const data = await plugins.fireHook('filter:parse.post', { postData: postData }); | 		const data = await plugins.fireHook('filter:parse.post', { postData: postData }); | ||||||
| 		data.postData.content = translator.escape(data.postData.content); | 		data.postData.content = translator.escape(data.postData.content); | ||||||
| 		if (global.env === 'production' && data.postData.pid) { | 		if (data.postData.pid) { | ||||||
| 			cache.set(pid, data.postData.content); | 			cache.set(pid, data.postData.content); | ||||||
| 		} | 		} | ||||||
| 		return data.postData; | 		return data.postData; | ||||||
|   | |||||||
| @@ -41,6 +41,9 @@ helpers.isUserAllowedTo = async function (privilege, uid, cid) { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| async function isUserAllowedToCids(privilege, uid, cids) { | async function isUserAllowedToCids(privilege, uid, cids) { | ||||||
|  | 	if (!privilege) { | ||||||
|  | 		return cids.map(() => false); | ||||||
|  | 	} | ||||||
| 	if (parseInt(uid, 10) <= 0) { | 	if (parseInt(uid, 10) <= 0) { | ||||||
| 		return await isSystemGroupAllowedToCids(privilege, uid, cids); | 		return await isSystemGroupAllowedToCids(privilege, uid, cids); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -61,6 +61,7 @@ function apiRoutes(router, middleware, controllers) { | |||||||
| 	router.get('/api/admin/users/csv', middleware.authenticate, helpers.tryRoute(controllers.admin.users.getCSV)); | 	router.get('/api/admin/users/csv', middleware.authenticate, helpers.tryRoute(controllers.admin.users.getCSV)); | ||||||
| 	router.get('/api/admin/groups/:groupname/csv', middleware.authenticate, helpers.tryRoute(controllers.admin.groups.getCSV)); | 	router.get('/api/admin/groups/:groupname/csv', middleware.authenticate, helpers.tryRoute(controllers.admin.groups.getCSV)); | ||||||
| 	router.get('/api/admin/analytics', middleware.authenticate, helpers.tryRoute(controllers.admin.dashboard.getAnalytics)); | 	router.get('/api/admin/analytics', middleware.authenticate, helpers.tryRoute(controllers.admin.dashboard.getAnalytics)); | ||||||
|  | 	router.get('/api/admin/advanced/cache/dump', middleware.authenticate, helpers.tryRoute(controllers.admin.cache.dump)); | ||||||
|  |  | ||||||
| 	const multipart = require('connect-multiparty'); | 	const multipart = require('connect-multiparty'); | ||||||
| 	const multipartMiddleware = multipart(); | 	const multipartMiddleware = multipart(); | ||||||
|   | |||||||
| @@ -8,3 +8,16 @@ SocketCache.clear = async function () { | |||||||
| 	require('../../groups').cache.reset(); | 	require('../../groups').cache.reset(); | ||||||
| 	require('../../cache').reset(); | 	require('../../cache').reset(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | SocketCache.toggle = async function (socket, data) { | ||||||
|  | 	const caches = { | ||||||
|  | 		post: require('../../posts/cache'), | ||||||
|  | 		object: require('../../database').objectCache, | ||||||
|  | 		group: require('../../groups').cache, | ||||||
|  | 		local: require('../../cache'), | ||||||
|  | 	}; | ||||||
|  | 	if (!caches[data.name]) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	caches[data.name].enabled = data.enabled; | ||||||
|  | }; | ||||||
|   | |||||||
| @@ -6,7 +6,13 @@ | |||||||
| 				<div class="panel panel-default"> | 				<div class="panel panel-default"> | ||||||
| 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> [[admin/advanced/cache:post-cache]]</div> | 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> [[admin/advanced/cache:post-cache]]</div> | ||||||
| 					<div class="panel-body"> | 					<div class="panel-body"> | ||||||
| 						<label>[[admin/advanced/cache:length-to-max]]</label><br/> | 						<div class="checkbox" data-name="post"> | ||||||
|  | 							<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect"> | ||||||
|  | 								<input class="mdl-switch__input" type="checkbox" {{{if postCache.enabled}}}checked{{{end}}}> | ||||||
|  | 								<span class="mdl-switch__label"><strong>[[admin/advanced/cache:enabled]]</strong></span> | ||||||
|  | 							</label> | ||||||
|  | 						</div> | ||||||
|  |  | ||||||
| 						<span>{postCache.length} / {postCache.max}</span><br/> | 						<span>{postCache.length} / {postCache.max}</span><br/> | ||||||
|  |  | ||||||
| 						<div class="progress"> | 						<div class="progress"> | ||||||
| @@ -21,16 +27,11 @@ | |||||||
|  |  | ||||||
| 						<hr/> | 						<hr/> | ||||||
|  |  | ||||||
| 						<label>[[admin/advanced/cache:posts-in-cache]]</label><br/> |  | ||||||
| 						<span>{postCache.itemCount}</span><br/> |  | ||||||
|  |  | ||||||
| 						<label>[[admin/advanced/cache:average-post-size]]</label><br/> |  | ||||||
| 						<span>{postCache.avgPostSize}</span><br/> |  | ||||||
|  |  | ||||||
| 						<div class="form-group"> | 						<div class="form-group"> | ||||||
| 							<label for="postCacheSize">[[admin/advanced/cache:post-cache-size]]</label> | 							<label for="postCacheSize">[[admin/advanced/cache:post-cache-size]]</label> | ||||||
| 							<input id="postCacheSize" type="text" class="form-control" value="" data-field="postCacheSize"> | 							<input id="postCacheSize" type="text" class="form-control" value="" data-field="postCacheSize"> | ||||||
| 						</div> | 						</div> | ||||||
|  | 						<a href="{config.relative_path}/api/admin/advanced/cache/dump?name=post" class="btn btn-default"><i class="fa fa-download"></i> [[admin/advanced/cache:download]]</a> | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
| @@ -40,7 +41,12 @@ | |||||||
| 				<div class="panel panel-default"> | 				<div class="panel panel-default"> | ||||||
| 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> Object Cache</div> | 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> Object Cache</div> | ||||||
| 					<div class="panel-body"> | 					<div class="panel-body"> | ||||||
| 						<label>[[admin/advanced/cache:length-to-max]]</label><br/> | 						<div class="checkbox" data-name="object"> | ||||||
|  | 							<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect"> | ||||||
|  | 								<input class="mdl-switch__input" type="checkbox" {{{if objectCache.enabled}}}checked{{{end}}}> | ||||||
|  | 								<span class="mdl-switch__label"><strong>[[admin/advanced/cache:enabled]]</strong></span> | ||||||
|  | 							</label> | ||||||
|  | 						</div> | ||||||
| 						<span>{objectCache.length} / {objectCache.max}</span><br/> | 						<span>{objectCache.length} / {objectCache.max}</span><br/> | ||||||
| 						<div class="progress"> | 						<div class="progress"> | ||||||
| 							<div class="progress-bar" role="progressbar" aria-valuenow="{objectCache.percentFull}" aria-valuemin="0" aria-valuemax="100" style="width: {objectCache.percentFull}%;"> | 							<div class="progress-bar" role="progressbar" aria-valuenow="{objectCache.percentFull}" aria-valuemin="0" aria-valuemax="100" style="width: {objectCache.percentFull}%;"> | ||||||
| @@ -51,6 +57,7 @@ | |||||||
| 						<label>Hits:</label> <span>{objectCache.hits}</span><br/> | 						<label>Hits:</label> <span>{objectCache.hits}</span><br/> | ||||||
| 						<label>Misses:</label> <span>{objectCache.misses}</span><br/> | 						<label>Misses:</label> <span>{objectCache.misses}</span><br/> | ||||||
| 						<label>Hit Ratio:</label> <span>{objectCache.hitRatio}</span><br/> | 						<label>Hit Ratio:</label> <span>{objectCache.hitRatio}</span><br/> | ||||||
|  | 						<a href="{config.relative_path}/api/admin/advanced/cache/dump?name=object" class="btn btn-default"><i class="fa fa-download"></i> [[admin/advanced/cache:download]]</a> | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
| @@ -59,8 +66,12 @@ | |||||||
| 				<div class="panel panel-default"> | 				<div class="panel panel-default"> | ||||||
| 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> Group Cache</div> | 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> Group Cache</div> | ||||||
| 					<div class="panel-body"> | 					<div class="panel-body"> | ||||||
|  | 						<div class="checkbox" data-name="group"> | ||||||
| 						<label>[[admin/advanced/cache:length-to-max]]</label><br/> | 							<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect"> | ||||||
|  | 								<input class="mdl-switch__input" type="checkbox" {{{if groupCache.enabled}}}checked{{{end}}}> | ||||||
|  | 								<span class="mdl-switch__label"><strong>[[admin/advanced/cache:enabled]]</strong></span> | ||||||
|  | 							</label> | ||||||
|  | 						</div> | ||||||
| 						<span>{groupCache.length} / {groupCache.max}</span><br/> | 						<span>{groupCache.length} / {groupCache.max}</span><br/> | ||||||
|  |  | ||||||
| 						<div class="progress"> | 						<div class="progress"> | ||||||
| @@ -72,6 +83,7 @@ | |||||||
| 						<label>Hits:</label> <span>{groupCache.hits}</span><br/> | 						<label>Hits:</label> <span>{groupCache.hits}</span><br/> | ||||||
| 						<label>Misses:</label> <span>{groupCache.misses}</span><br/> | 						<label>Misses:</label> <span>{groupCache.misses}</span><br/> | ||||||
| 						<label>Hit Ratio:</label> <span>{groupCache.hitRatio}</span><br/> | 						<label>Hit Ratio:</label> <span>{groupCache.hitRatio}</span><br/> | ||||||
|  | 						<a href="{config.relative_path}/api/admin/advanced/cache/dump?name=group" class="btn btn-default"><i class="fa fa-download"></i> [[admin/advanced/cache:download]]</a> | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
| @@ -79,8 +91,12 @@ | |||||||
| 				<div class="panel panel-default"> | 				<div class="panel panel-default"> | ||||||
| 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> Local Cache</div> | 					<div class="panel-heading"><i class="fa fa-calendar-o"></i> Local Cache</div> | ||||||
| 					<div class="panel-body"> | 					<div class="panel-body"> | ||||||
|  | 						<div class="checkbox" data-name="local"> | ||||||
| 						<label>[[admin/advanced/cache:length-to-max]]</label><br/> | 							<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect"> | ||||||
|  | 								<input class="mdl-switch__input" type="checkbox" {{{if localCache.enabled}}}checked{{{end}}}> | ||||||
|  | 								<span class="mdl-switch__label"><strong>[[admin/advanced/cache:enabled]]</strong></span> | ||||||
|  | 							</label> | ||||||
|  | 						</div> | ||||||
| 						<span>{localCache.length} / {localCache.max}</span><br/> | 						<span>{localCache.length} / {localCache.max}</span><br/> | ||||||
|  |  | ||||||
| 						<div class="progress"> | 						<div class="progress"> | ||||||
| @@ -92,11 +108,7 @@ | |||||||
| 						<label>Hits:</label> <span>{localCache.hits}</span><br/> | 						<label>Hits:</label> <span>{localCache.hits}</span><br/> | ||||||
| 						<label>Misses:</label> <span>{localCache.misses}</span><br/> | 						<label>Misses:</label> <span>{localCache.misses}</span><br/> | ||||||
| 						<label>Hit Ratio:</label> <span>{localCache.hitRatio}</span><br/> | 						<label>Hit Ratio:</label> <span>{localCache.hitRatio}</span><br/> | ||||||
|  | 						<a href="{config.relative_path}/api/admin/advanced/cache/dump?name=local" class="btn btn-default"><i class="fa fa-download"></i> [[admin/advanced/cache:download]]</a> | ||||||
| 						<!-- IF localCache.dump --> |  | ||||||
| 						<pre>{localCache.dump}</pre> |  | ||||||
| 						<!-- ENDIF localCache.dump --> |  | ||||||
|  |  | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ describe('meta', function () { | |||||||
| 	var herpUid; | 	var herpUid; | ||||||
|  |  | ||||||
| 	before(function (done) { | 	before(function (done) { | ||||||
| 		Groups.resetCache(); | 		Groups.cache.reset(); | ||||||
| 		// Create 3 users: 1 admin, 2 regular | 		// Create 3 users: 1 admin, 2 regular | ||||||
| 		async.series([ | 		async.series([ | ||||||
| 			async.apply(User.create, { username: 'foo', password: 'barbar' }),	// admin | 			async.apply(User.create, { username: 'foo', password: 'barbar' }),	// admin | ||||||
|   | |||||||
| @@ -168,7 +168,7 @@ async function setupMockDefaults() { | |||||||
| 	const meta = require('../../src/meta'); | 	const meta = require('../../src/meta'); | ||||||
| 	await db.emptydb(); | 	await db.emptydb(); | ||||||
|  |  | ||||||
| 	require('../../src/groups').resetCache(); | 	require('../../src/groups').cache.reset(); | ||||||
| 	require('../../src/posts/cache').reset(); | 	require('../../src/posts/cache').reset(); | ||||||
| 	require('../../src/cache').reset(); | 	require('../../src/cache').reset(); | ||||||
| 	winston.info('test_database flushed'); | 	winston.info('test_database flushed'); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user