From 7eba5e1fa81c8e54cb8fe298a96e8070afa50921 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 4 Feb 2020 15:00:47 +0100 Subject: Add model cache for video When fetching only immutable attributes --- server/models/model-cache.ts | 39 +++++++++++++++++++++++++++++++++++++-- server/models/video/video.ts | 30 +++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) (limited to 'server/models') diff --git a/server/models/model-cache.ts b/server/models/model-cache.ts index bfa163b6b..8afe3834f 100644 --- a/server/models/model-cache.ts +++ b/server/models/model-cache.ts @@ -6,6 +6,10 @@ type ModelCacheType = 'local-account-name' | 'local-actor-name' | 'local-actor-url' + | 'video-immutable' + +type DeleteKey = + 'video' class ModelCache { @@ -14,7 +18,14 @@ class ModelCache { private readonly localCache: { [id in ModelCacheType]: Map } = { 'local-account-name': new Map(), 'local-actor-name': new Map(), - 'local-actor-url': new Map() + 'local-actor-url': new Map(), + 'video-immutable': new Map() + } + + private readonly deleteIds: { + [deleteKey in DeleteKey]: Map + } = { + video: new Map() } private constructor () { @@ -29,8 +40,9 @@ class ModelCache { key: string fun: () => Bluebird whitelist?: () => boolean + deleteKey?: DeleteKey }) { - const { cacheType, key, fun, whitelist } = options + const { cacheType, key, fun, whitelist, deleteKey } = options if (whitelist && whitelist() !== true) return fun() @@ -42,11 +54,34 @@ class ModelCache { } return fun().then(m => { + if (!m) return m + if (!whitelist || whitelist()) cache.set(key, m) + if (deleteKey) { + const map = this.deleteIds[deleteKey] + if (!map.has(m.id)) map.set(m.id, []) + + const a = map.get(m.id) + a.push({ cacheType, key }) + } + return m }) } + + invalidateCache (deleteKey: DeleteKey, modelId: number) { + const map = this.deleteIds[deleteKey] + + if (!map.has(modelId)) return + + for (const toDelete of map.get(modelId)) { + logger.debug('Removing %s -> %d of model cache %s -> %s.', deleteKey, modelId, toDelete.cacheType, toDelete.key) + this.localCache[toDelete.cacheType].delete(toDelete.key) + } + + map.delete(modelId) + } } export { diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 1ec8d717e..9e02d163f 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -120,7 +120,7 @@ import { MVideoFormattableDetails, MVideoForUser, MVideoFullLight, - MVideoIdThumbnail, + MVideoIdThumbnail, MVideoImmutable, MVideoThumbnail, MVideoThumbnailBlacklist, MVideoWithAllFiles, @@ -132,6 +132,7 @@ import { MThumbnail } from '../../typings/models/video/thumbnail' import { VideoFile } from '@shared/models/videos/video-file.model' import { getHLSDirectory, getTorrentFileName, getTorrentFilePath, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' import validator from 'validator' +import { ModelCache } from '@server/models/model-cache' export enum ScopeNames { AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS', @@ -1074,6 +1075,11 @@ export class VideoModel extends Model { return undefined } + @BeforeDestroy + static invalidateCache (instance: VideoModel) { + ModelCache.Instance.invalidateCache('video', instance.id) + } + static listLocal (): Bluebird { const query = { where: { @@ -1468,6 +1474,28 @@ export class VideoModel extends Model { ]).findOne(options) } + static loadImmutableAttributes (id: number | string, t?: Transaction): Bluebird { + const fun = () => { + const where = buildWhereIdOrUUID(id) + const options = { + attributes: [ + 'id', 'url', 'uuid' + ], + where, + transaction: t + } + + return VideoModel.unscoped().findOne(options) + } + + return ModelCache.Instance.doCache({ + cacheType: 'video-immutable', + key: '' + id, + deleteKey: 'video', + fun + }) + } + static loadWithRights (id: number | string, t?: Transaction): Bluebird { const where = buildWhereIdOrUUID(id) const options = { -- cgit v1.2.3