mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-06 22:15:48 +01:00
cache group membership methods
groups.isMember groups.isMembers groups.isMemberOfGroups clear cache for user on group.join & group.leave
This commit is contained in:
@@ -16,7 +16,7 @@ var adminController = {
|
|||||||
logs: require('./admin/logs'),
|
logs: require('./admin/logs'),
|
||||||
errors: require('./admin/errors'),
|
errors: require('./admin/errors'),
|
||||||
database: require('./admin/database'),
|
database: require('./admin/database'),
|
||||||
postCache: require('./admin/postCache'),
|
cache: require('./admin/cache'),
|
||||||
plugins: require('./admin/plugins'),
|
plugins: require('./admin/plugins'),
|
||||||
languages: require('./admin/languages'),
|
languages: require('./admin/languages'),
|
||||||
settings: require('./admin/settings'),
|
settings: require('./admin/settings'),
|
||||||
|
|||||||
36
src/controllers/admin/cache.js
Normal file
36
src/controllers/admin/cache.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var cacheController = {};
|
||||||
|
|
||||||
|
cacheController.get = function(req, res, next) {
|
||||||
|
var postCache = require('../../posts/cache');
|
||||||
|
var groupCache = require('../../groups').cache;
|
||||||
|
|
||||||
|
var avgPostSize = 0;
|
||||||
|
var percentFull = 0;
|
||||||
|
if (postCache.itemCount > 0) {
|
||||||
|
avgPostSize = parseInt((postCache.length / postCache.itemCount), 10);
|
||||||
|
percentFull = ((postCache.length / postCache.max) * 100).toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.render('admin/advanced/cache', {
|
||||||
|
postCache: {
|
||||||
|
length: postCache.length,
|
||||||
|
max: postCache.max,
|
||||||
|
itemCount: postCache.itemCount,
|
||||||
|
percentFull: percentFull,
|
||||||
|
avgPostSize: avgPostSize,
|
||||||
|
dump: req.query.debug ? postCache.dump() : undefined
|
||||||
|
},
|
||||||
|
groupCache: {
|
||||||
|
length: groupCache.length,
|
||||||
|
max: groupCache.max,
|
||||||
|
itemCount: groupCache.itemCount,
|
||||||
|
percentFull: ((groupCache.length / groupCache.max) * 100).toFixed(2),
|
||||||
|
dump: req.query.debug ? groupCache.dump() : undefined
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = cacheController;
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var postCacheController = {};
|
|
||||||
|
|
||||||
postCacheController.get = function(req, res, next) {
|
|
||||||
var cache = require('../../posts/cache');
|
|
||||||
var avgPostSize = 0;
|
|
||||||
var percentFull = 0;
|
|
||||||
if (cache.itemCount > 0) {
|
|
||||||
avgPostSize = parseInt((cache.length / cache.itemCount), 10);
|
|
||||||
percentFull = ((cache.length / cache.max) * 100).toFixed(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.render('admin/advanced/post-cache', {
|
|
||||||
cache: {
|
|
||||||
length: cache.length,
|
|
||||||
max: cache.max,
|
|
||||||
itemCount: cache.itemCount,
|
|
||||||
percentFull: percentFull,
|
|
||||||
avgPostSize: avgPostSize
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = postCacheController;
|
|
||||||
@@ -8,10 +8,21 @@ var user = require('../user');
|
|||||||
var utils = require('../../public/src/utils');
|
var utils = require('../../public/src/utils');
|
||||||
var plugins = require('../plugins');
|
var plugins = require('../plugins');
|
||||||
var notifications = require('../notifications');
|
var notifications = require('../notifications');
|
||||||
var db = require('./../database');
|
var db = require('../database');
|
||||||
|
|
||||||
|
var pubsub = require('../pubsub');
|
||||||
|
var LRU = require('lru-cache');
|
||||||
|
|
||||||
|
var cache = LRU({
|
||||||
|
max: 200,
|
||||||
|
maxAge: 1000 * 60 * 60
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports = function(Groups) {
|
module.exports = function(Groups) {
|
||||||
|
|
||||||
|
Groups.cache = cache;
|
||||||
|
|
||||||
Groups.join = function(groupName, uid, callback) {
|
Groups.join = function(groupName, uid, callback) {
|
||||||
callback = callback || function() {};
|
callback = callback || function() {};
|
||||||
|
|
||||||
@@ -69,6 +80,7 @@ module.exports = function(Groups) {
|
|||||||
async.parallel(tasks, next);
|
async.parallel(tasks, next);
|
||||||
},
|
},
|
||||||
function(results, next) {
|
function(results, next) {
|
||||||
|
clearCache(uid);
|
||||||
setGroupTitleIfNotSet(groupName, uid, next);
|
setGroupTitleIfNotSet(groupName, uid, next);
|
||||||
},
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
@@ -222,6 +234,7 @@ module.exports = function(Groups) {
|
|||||||
], next);
|
], next);
|
||||||
},
|
},
|
||||||
function(results, next) {
|
function(results, next) {
|
||||||
|
clearCache(uid);
|
||||||
Groups.getGroupFields(groupName, ['hidden', 'memberCount'], next);
|
Groups.getGroupFields(groupName, ['hidden', 'memberCount'], next);
|
||||||
},
|
},
|
||||||
function(groupData, next) {
|
function(groupData, next) {
|
||||||
@@ -296,26 +309,130 @@ module.exports = function(Groups) {
|
|||||||
}), callback);
|
}), callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Groups.resetCache = function() {
|
||||||
|
pubsub.publish('group:cache:reset');
|
||||||
|
cache.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
pubsub.on('group:cache:reset', function() {
|
||||||
|
cache.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
function clearCache(uid) {
|
||||||
|
pubsub.publish('group:cache:del', {uid: uid});
|
||||||
|
cache.del(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pubsub.on('group:cache:del', function(data) {
|
||||||
|
cache.del(data.uid);
|
||||||
|
});
|
||||||
|
|
||||||
Groups.isMember = function(uid, groupName, callback) {
|
Groups.isMember = function(uid, groupName, callback) {
|
||||||
if (!uid || parseInt(uid, 10) <= 0) {
|
if (!uid || parseInt(uid, 10) <= 0) {
|
||||||
return callback(null, false);
|
return callback(null, false);
|
||||||
}
|
}
|
||||||
db.isSortedSetMember('group:' + groupName + ':members', uid, callback);
|
|
||||||
|
var cachedData = cache.get(uid);
|
||||||
|
|
||||||
|
if (cachedData && cachedData.hasOwnProperty(groupName)) {
|
||||||
|
return process.nextTick(callback, null, cachedData[groupName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.isSortedSetMember('group:' + groupName + ':members', uid, function(err, isMember) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedData = cachedData || {};
|
||||||
|
cachedData[groupName] = isMember;
|
||||||
|
cache.set(uid, cachedData);
|
||||||
|
callback(null, isMember);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Groups.isMembers = function(uids, groupName, callback) {
|
Groups.isMembers = function(uids, groupName, callback) {
|
||||||
db.isSortedSetMembers('group:' + groupName + ':members', uids, callback);
|
if (!groupName || !uids.length) {
|
||||||
|
return callback(null, uids.map(function() {return false;}));
|
||||||
|
}
|
||||||
|
|
||||||
|
var cachedUids = {};
|
||||||
|
var nonCachedUids = [];
|
||||||
|
uids.forEach(function(uid) {
|
||||||
|
cachedUids[uid] = cache.get(uid);
|
||||||
|
if (!cachedUids[uid] || !cachedUids[uid].hasOwnProperty(groupName)) {
|
||||||
|
nonCachedUids.push(uid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!nonCachedUids.length) {
|
||||||
|
var result = uids.map(function(uid) {
|
||||||
|
return cachedUids[uid] && cachedUids[uid][groupName];
|
||||||
|
});
|
||||||
|
return process.nextTick(callback, null, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.isSortedSetMembers('group:' + groupName + ':members', nonCachedUids, function(err, isMembers) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
nonCachedUids.forEach(function(uid, index) {
|
||||||
|
cachedUids[uid] = cachedUids[uid] || {};
|
||||||
|
cachedUids[uid][groupName] = isMembers[index];
|
||||||
|
cache.set(uid, cachedUids[uid]);
|
||||||
|
});
|
||||||
|
|
||||||
|
var result = uids.map(function(uid) {
|
||||||
|
return cachedUids[uid][groupName];
|
||||||
|
});
|
||||||
|
|
||||||
|
callback(null, result);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Groups.isMemberOfGroups = function(uid, groups, callback) {
|
Groups.isMemberOfGroups = function(uid, groups, callback) {
|
||||||
if (!uid || parseInt(uid, 10) <= 0) {
|
if (!uid || parseInt(uid, 10) <= 0 || !groups.length) {
|
||||||
return callback(null, groups.map(function() {return false;}));
|
return callback(null, groups.map(function() {return false;}));
|
||||||
}
|
}
|
||||||
groups = groups.map(function(groupName) {
|
|
||||||
|
var cachedData = cache.get(uid);
|
||||||
|
var nonCachedGroups = [];
|
||||||
|
if (cachedData) {
|
||||||
|
groups.forEach(function(groupName) {
|
||||||
|
if (!cachedData.hasOwnProperty(groupName)) {
|
||||||
|
nonCachedGroups.push(groupName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
nonCachedGroups = groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
// are they all cached?
|
||||||
|
if (cachedData && !nonCachedGroups.length) {
|
||||||
|
var result = groups.map(function(groupName) {
|
||||||
|
return cachedData[groupName];
|
||||||
|
});
|
||||||
|
return process.nextTick(callback, null, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonCachedGroupsMemberSets = nonCachedGroups.map(function(groupName) {
|
||||||
return 'group:' + groupName + ':members';
|
return 'group:' + groupName + ':members';
|
||||||
});
|
});
|
||||||
|
|
||||||
db.isMemberOfSortedSets(groups, uid, callback);
|
db.isMemberOfSortedSets(nonCachedGroupsMemberSets, uid, function(err, isMembers) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
cachedData = cachedData || {};
|
||||||
|
nonCachedGroups.forEach(function(groupName, index) {
|
||||||
|
cachedData[groupName] = isMembers[index];
|
||||||
|
});
|
||||||
|
cache.set(uid, cachedData);
|
||||||
|
var result = groups.map(function(groupName) {
|
||||||
|
return cachedData[groupName];
|
||||||
|
});
|
||||||
|
callback(null, result);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Groups.getMemberCount = function(groupName, callback) {
|
Groups.getMemberCount = function(groupName, callback) {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ function addRoutes(router, middleware, controllers) {
|
|||||||
router.get('/advanced/logs', middlewares, controllers.admin.logs.get);
|
router.get('/advanced/logs', middlewares, controllers.admin.logs.get);
|
||||||
router.get('/advanced/errors', middlewares, controllers.admin.errors.get);
|
router.get('/advanced/errors', middlewares, controllers.admin.errors.get);
|
||||||
router.get('/advanced/errors/export', middlewares, controllers.admin.errors.export);
|
router.get('/advanced/errors/export', middlewares, controllers.admin.errors.export);
|
||||||
router.get('/advanced/post-cache', middlewares, controllers.admin.postCache.get);
|
router.get('/advanced/cache', middlewares, controllers.admin.cache.get);
|
||||||
|
|
||||||
router.get('/development/logger', middlewares, controllers.admin.logger.get);
|
router.get('/development/logger', middlewares, controllers.admin.logger.get);
|
||||||
router.get('/development/info', middlewares, controllers.admin.info.get);
|
router.get('/development/info', middlewares, controllers.admin.info.get);
|
||||||
|
|||||||
46
src/views/admin/advanced/cache.tpl
Normal file
46
src/views/admin/advanced/cache.tpl
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
<div class="post-cache">
|
||||||
|
<div class="col-lg-9">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"><i class="fa fa-calendar-o"></i> Post Cache</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<label>Posts in Cache</label><br/>
|
||||||
|
<span>{postCache.itemCount}</span><br/>
|
||||||
|
|
||||||
|
<label>Average Post Size</label><br/>
|
||||||
|
<span>{postCache.avgPostSize}</span><br/>
|
||||||
|
|
||||||
|
<label>Length / Max</label><br/>
|
||||||
|
<span>{postCache.length} / {postCache.max}</span><br/>
|
||||||
|
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar" role="progressbar" aria-valuenow="{postCache.percentFull}" aria-valuemin="0" aria-valuemax="100" style="width: {postCache.percentFull}%;">
|
||||||
|
{postCache.percentFull}% Full
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"><i class="fa fa-calendar-o"></i> Group Cache</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<label>Users in Cache</label><br/>
|
||||||
|
<span>{groupCache.itemCount}</span><br/>
|
||||||
|
|
||||||
|
<label>Length / Max</label><br/>
|
||||||
|
<span>{groupCache.length} / {groupCache.max}</span><br/>
|
||||||
|
|
||||||
|
<div class="progress">
|
||||||
|
<div class="progress-bar" role="progressbar" aria-valuenow="{groupCache.percentFull}" aria-valuemin="0" aria-valuemax="100" style="width: {groupCache.percentFull}%;">
|
||||||
|
{groupCache.percentFull}% Full
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
<div class="post-cache">
|
|
||||||
<div class="col-lg-9">
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading"><i class="fa fa-calendar-o"></i> Post Cache</div>
|
|
||||||
<div class="panel-body" data-next="{next}">
|
|
||||||
|
|
||||||
<label>Posts in Cache</label><br/>
|
|
||||||
<span>{cache.itemCount}</span><br/>
|
|
||||||
|
|
||||||
<label>Average Post Size</label><br/>
|
|
||||||
<span>{cache.avgPostSize}</span><br/>
|
|
||||||
|
|
||||||
<label>Length / Max</label><br/>
|
|
||||||
<span>{cache.length} / {cache.max}</span><br/>
|
|
||||||
|
|
||||||
<div class="progress">
|
|
||||||
<div class="progress-bar" role="progressbar" aria-valuenow="{cache.percentFull}" aria-valuemin="0" aria-valuemax="100" style="width: {cache.percentFull}%;">
|
|
||||||
{cache.percentFull}% Full
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
<li><a href="{relative_path}/admin/advanced/events">Events</a></li>
|
<li><a href="{relative_path}/admin/advanced/events">Events</a></li>
|
||||||
<li><a href="{relative_path}/admin/advanced/logs">Logs</a></li>
|
<li><a href="{relative_path}/admin/advanced/logs">Logs</a></li>
|
||||||
<li><a href="{relative_path}/admin/advanced/errors">Errors</a></li>
|
<li><a href="{relative_path}/admin/advanced/errors">Errors</a></li>
|
||||||
<li><a href="{relative_path}/admin/advanced/post-cache">Post Cache</a></li>
|
<li><a href="{relative_path}/admin/advanced/cache">Cache</a></li>
|
||||||
<!-- IF env -->
|
<!-- IF env -->
|
||||||
<li><a href="{relative_path}/admin/development/logger">Logger</a></li>
|
<li><a href="{relative_path}/admin/development/logger">Logger</a></li>
|
||||||
<!-- ENDIF env -->
|
<!-- ENDIF env -->
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
<li><a href="{relative_path}/admin/advanced/events">Events</a></li>
|
<li><a href="{relative_path}/admin/advanced/events">Events</a></li>
|
||||||
<li><a href="{relative_path}/admin/advanced/logs">Logs</a></li>
|
<li><a href="{relative_path}/admin/advanced/logs">Logs</a></li>
|
||||||
<li><a href="{relative_path}/admin/advanced/errors">Errors</a></li>
|
<li><a href="{relative_path}/admin/advanced/errors">Errors</a></li>
|
||||||
<li><a href="{relative_path}/admin/advanced/post-cache">Post Cache</a></li>
|
<li><a href="{relative_path}/admin/advanced/cache">Cache</a></li>
|
||||||
<!-- IF env -->
|
<!-- IF env -->
|
||||||
<li><a href="{relative_path}/admin/development/logger">Logger</a></li>
|
<li><a href="{relative_path}/admin/development/logger">Logger</a></li>
|
||||||
<!-- ENDIF env -->
|
<!-- ENDIF env -->
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ describe('User', function() {
|
|||||||
testCid;
|
testCid;
|
||||||
|
|
||||||
before(function(done) {
|
before(function(done) {
|
||||||
|
var groups = require('../src/groups');
|
||||||
|
groups.resetCache();
|
||||||
|
|
||||||
Categories.create({
|
Categories.create({
|
||||||
name: 'Test Category',
|
name: 'Test Category',
|
||||||
description: 'A test',
|
description: 'A test',
|
||||||
@@ -37,7 +40,7 @@ describe('User', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(function(){
|
beforeEach(function() {
|
||||||
userData = {
|
userData = {
|
||||||
username: 'John Smith',
|
username: 'John Smith',
|
||||||
fullname: 'John Smith McNamara',
|
fullname: 'John Smith McNamara',
|
||||||
|
|||||||
Reference in New Issue
Block a user