mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-06 05:55: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'),
|
||||
errors: require('./admin/errors'),
|
||||
database: require('./admin/database'),
|
||||
postCache: require('./admin/postCache'),
|
||||
cache: require('./admin/cache'),
|
||||
plugins: require('./admin/plugins'),
|
||||
languages: require('./admin/languages'),
|
||||
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 plugins = require('../plugins');
|
||||
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) {
|
||||
|
||||
Groups.cache = cache;
|
||||
|
||||
Groups.join = function(groupName, uid, callback) {
|
||||
callback = callback || function() {};
|
||||
|
||||
@@ -69,6 +80,7 @@ module.exports = function(Groups) {
|
||||
async.parallel(tasks, next);
|
||||
},
|
||||
function(results, next) {
|
||||
clearCache(uid);
|
||||
setGroupTitleIfNotSet(groupName, uid, next);
|
||||
},
|
||||
function(next) {
|
||||
@@ -222,6 +234,7 @@ module.exports = function(Groups) {
|
||||
], next);
|
||||
},
|
||||
function(results, next) {
|
||||
clearCache(uid);
|
||||
Groups.getGroupFields(groupName, ['hidden', 'memberCount'], next);
|
||||
},
|
||||
function(groupData, next) {
|
||||
@@ -296,26 +309,130 @@ module.exports = function(Groups) {
|
||||
}), 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) {
|
||||
if (!uid || parseInt(uid, 10) <= 0) {
|
||||
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) {
|
||||
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) {
|
||||
if (!uid || parseInt(uid, 10) <= 0) {
|
||||
if (!uid || parseInt(uid, 10) <= 0 || !groups.length) {
|
||||
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';
|
||||
});
|
||||
|
||||
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) {
|
||||
|
||||
@@ -85,7 +85,7 @@ function addRoutes(router, middleware, controllers) {
|
||||
router.get('/advanced/logs', middlewares, controllers.admin.logs.get);
|
||||
router.get('/advanced/errors', middlewares, controllers.admin.errors.get);
|
||||
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/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/logs">Logs</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 -->
|
||||
<li><a href="{relative_path}/admin/development/logger">Logger</a></li>
|
||||
<!-- ENDIF env -->
|
||||
@@ -245,7 +245,7 @@
|
||||
<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/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 -->
|
||||
<li><a href="{relative_path}/admin/development/logger">Logger</a></li>
|
||||
<!-- ENDIF env -->
|
||||
|
||||
@@ -23,6 +23,9 @@ describe('User', function() {
|
||||
testCid;
|
||||
|
||||
before(function(done) {
|
||||
var groups = require('../src/groups');
|
||||
groups.resetCache();
|
||||
|
||||
Categories.create({
|
||||
name: 'Test Category',
|
||||
description: 'A test',
|
||||
@@ -37,7 +40,7 @@ describe('User', function() {
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function(){
|
||||
beforeEach(function() {
|
||||
userData = {
|
||||
username: 'John Smith',
|
||||
fullname: 'John Smith McNamara',
|
||||
|
||||
Reference in New Issue
Block a user