perf: only load thumbs for topics that actually have thumbs

v1.18.x
Barış Soner Uşaklı 4 years ago
parent dc14528427
commit 7eebcbdbbc

@ -82,7 +82,7 @@ Topics.getTopicsByTids = async function (tids, options) {
user.getMultipleUserSettings(uids),
categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'backgroundImage', 'imageClass', 'bgColor', 'color', 'disabled']),
loadGuestHandles(),
Topics.thumbs.get(tids),
Topics.thumbs.load(topics),
]);
users.forEach((userObj, idx) => {
@ -167,11 +167,11 @@ Topics.getTopicWithPosts = async function (topicData, set, uid, start, stop, rev
getDeleter(topicData),
getMerger(topicData),
getRelated(topicData, uid),
Topics.thumbs.get(topicData.tid),
Topics.thumbs.load([topicData]),
Topics.events.get(topicData.tid),
]);
topicData.thumbs = thumbs;
topicData.thumbs = thumbs[0];
topicData.posts = posts;
topicData.events = events;
topicData.category = category;

@ -1,6 +1,7 @@
'use strict';
const _ = require('lodash');
const nconf = require('nconf');
const path = require('path');
const validator = require('validator');
@ -19,6 +20,14 @@ Thumbs.exists = async function (tid, path) {
return db.isSortedSetMember(`topic:${tid}:thumbs`, path);
};
Thumbs.load = async function (topicData) {
const topicsWithThumbs = topicData.filter(t => parseInt(t.numThumbs, 10) > 0);
const tidsWithThumbs = topicsWithThumbs.map(t => t.tid);
const thumbs = await Thumbs.get(tidsWithThumbs);
const tidToThumbs = _.zipObject(tidsWithThumbs, thumbs);
return topicData.map(t => tidToThumbs[t.tid] || []);
};
Thumbs.get = async function (tids) {
// Allow singular or plural usage
let singular = false;
@ -27,14 +36,14 @@ Thumbs.get = async function (tids) {
singular = true;
}
if (!meta.config.allowTopicsThumbnail) {
if (!meta.config.allowTopicsThumbnail || !tids.length) {
return singular ? [] : tids.map(() => []);
}
const hasTimestampPrefix = /^\d+-/;
const upload_url = nconf.get('relative_path') + nconf.get('upload_url');
const sets = tids.map(tid => `${validator.isUUID(String(tid)) ? 'draft' : 'topic'}:${tid}:thumbs`);
const thumbs = await Promise.all(sets.map(set => getThumbs(set)));
const thumbs = await Promise.all(sets.map(getThumbs));
let response = thumbs.map((thumbSet, idx) => thumbSet.map(thumb => ({
id: tids[idx],
name: (() => {
@ -69,13 +78,15 @@ Thumbs.associate = async function ({ id, path: relativePath, url }) {
if (relativePath) {
value = value.replace(nconf.get('upload_path'), '');
}
const topics = require('.');
await db.sortedSetAdd(set, numThumbs, value);
if (!isDraft) {
await topics.setTopicField(id, 'numThumbs', numThumbs);
}
cache.del(set);
// Associate thumbnails with the main pid (only on local upload)
if (!isDraft && relativePath) {
const topics = require('.');
const mainPid = (await topics.getMainPids([id]))[0];
posts.uploads.associate(mainPid, relativePath.replace('/files/', ''));
}
@ -110,6 +121,10 @@ Thumbs.delete = async function (id, relativePath) {
// Dissociate thumbnails with the main pid
if (!isDraft) {
const topics = require('.');
const numThumbs = await db.sortedSetCard(set);
if (!numThumbs) {
await db.deleteObjectField('topic:' + id, 'numThumbs');
}
const mainPid = (await topics.getMainPids([id]))[0];
posts.uploads.dissociate(mainPid, relativePath.replace('/files/', ''));
}

@ -0,0 +1,29 @@
'use strict';
const _ = require('lodash');
const db = require('../../database');
const batch = require('../../batch');
module.exports = {
name: 'Store number of thumbs a topic has in the topic object',
timestamp: Date.UTC(2021, 1, 7),
method: async function () {
const progress = this.progress;
await batch.processSortedSet('topics:tid', async function (tids) {
const keys = tids.map(tid => 'topic:' + tid + ':thumbs');
const counts = await db.sortedSetsCard(keys);
const tidToCount = _.zip(tids, counts);
const tidsWithThumbs = tids.filter((t, i) => counts[i] > 0);
await db.setObjectBulk(
tidsWithThumbs.map(tid => 'topic:' + tid),
tidsWithThumbs.map(tid => ({ numThumbs: tidToCount[tid] }))
);
progress.incr(tids.length);
}, {
batch: 500,
progress: progress,
});
},
};
Loading…
Cancel
Save