fix: emoji cache

This commit is contained in:
Namekuji 2023-08-09 08:15:26 -04:00
parent 746e2fac41
commit 63c445554a
No known key found for this signature in database
GPG key ID: 1D62332C07FBA532
7 changed files with 58 additions and 22 deletions

View file

@ -137,7 +137,7 @@ export const prepared = {
select: {
byNoteId: `SELECT * FROM reaction WHERE "noteId" IN ?`,
byUserId: `SELECT * FROM reaction_by_userid WHERE "userId" IN ?`,
byNoteAndUser: `SELECT * FROM reaction WHERE "noteId" = ? AND "userId" = ?`,
byNoteAndUser: `SELECT * FROM reaction WHERE "noteId" IN ? AND "userId" IN ?`,
byId: `SELECT * FROM reaction WHERE "id" IN ?`,
},
delete: `DELETE FROM reaction WHERE "noteId" = ? AND "userId" = ?`,

View file

@ -36,6 +36,12 @@ export class Cache<T> {
await commander.set(_key, _value, "EX", this.ttl);
}
public async exists(...keys: string[]): Promise<boolean> {
return (
(await redisClient.exists(keys.map((key) => this.prefixedKey(key)))) > 0
);
}
public async get(key: string | null, renew = false): Promise<T | undefined> {
const _key = this.prefixedKey(key);
const cached = await redisClient.getBuffer(_key);

View file

@ -152,9 +152,12 @@ export function aggregateNoteEmojis(notes: Note[]) {
export async function prefetchEmojis(
emojis: { name: string; host: string | null }[],
): Promise<void> {
const notCachedEmojis = emojis.filter(
async (emoji) => !(await EmojiCache.get(`${emoji.name} ${emoji.host}`)),
);
const notCachedEmojis: { name: string; host: string | null }[] = [];
for (const emoji of emojis) {
if (!(await EmojiCache.exists(`${emoji.name} ${emoji.host}`))) {
notCachedEmojis.push(emoji);
}
}
const emojisQuery: any[] = [];
const hosts = new Set(notCachedEmojis.map((e) => e.host));
for (const host of hosts) {

View file

@ -28,10 +28,11 @@ import {
import { db } from "@/db/postgre.js";
import { IdentifiableError } from "@/misc/identifiable-error.js";
import {
ScyllaNote,
type ScyllaNote,
parseScyllaNote,
prepared,
scyllaClient,
parseScyllaReaction,
} from "@/db/scylla.js";
import { LocalFollowingsCache } from "@/misc/cache.js";
import { userByIdCache } from "@/services/user-cache.js";
@ -91,10 +92,22 @@ async function populateMyReaction(
// 実装上抜けがあるだけかもしれないので、「ヒントに含まれてなかったら(=undefinedなら)return」のようにはしない
}
const reaction = await NoteReactions.findOneBy({
let reaction: NoteReaction | null = null;
if (scyllaClient) {
const result = await scyllaClient.execute(
prepared.reaction.select.byNoteAndUser,
[[note.id], [meId]],
{ prepare: true },
);
if (result.rowLength > 0) {
reaction = parseScyllaReaction(result.first());
}
} else {
reaction = await NoteReactions.findOneBy({
userId: meId,
noteId: note.id,
});
}
if (reaction) {
return convertLegacyReaction(reaction.reaction);
@ -358,10 +371,20 @@ export const NoteRepository = db.getRepository(Note).extend({
.filter((n) => !!n.renoteId)
.map((n) => n.renoteId) as string[];
const targets = [...notes.map((n) => n.id), ...renoteIds];
const myReactions = await NoteReactions.findBy({
let myReactions: NoteReaction[] = [];
if (scyllaClient) {
const result = await scyllaClient.execute(
prepared.reaction.select.byNoteAndUser,
[targets, [meId]],
{ prepare: true },
);
myReactions = result.rows.map(parseScyllaReaction);
} else {
myReactions = await NoteReactions.findBy({
userId: meId,
noteId: In(targets),
});
}
for (const target of targets) {
myReactionsMap.set(

View file

@ -1,5 +1,4 @@
import type { FindOptionsWhere } from "typeorm";
import { DeepPartial } from "typeorm";
import { NoteReactions } from "@/models/index.js";
import type { NoteReaction } from "@/models/entities/note-reaction.js";
import define from "../../define.js";

View file

@ -2,6 +2,7 @@ import { Notes } from "@/models/index.js";
import define from "../../define.js";
import { getNote } from "../../common/getters.js";
import { ApiError } from "../../error.js";
import { scyllaClient } from "@/db/scylla.js";
export const meta = {
tags: ["notes"],
@ -44,6 +45,7 @@ export default define(meta, paramDef, async (ps, user) => {
return await Notes.pack(note, user, {
// FIXME: packing with detail may throw an error if the reply or renote is not visible (#8774)
detail: true,
scyllaNote: !!scyllaClient
}).catch((err) => {
if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24")
throw new ApiError(meta.errors.noSuchNote);

View file

@ -22,7 +22,7 @@ import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js
import type { NoteReaction } from "@/models/entities/note-reaction.js";
import { IdentifiableError } from "@/misc/identifiable-error.js";
import { prepared, scyllaClient } from "@/db/scylla.js";
import { populateEmojis } from "@/misc/populate-emojis.js";
import { EmojiCache } from "@/misc/populate-emojis.js";
export default async (
user: { id: User["id"]; host: User["host"] },
@ -137,13 +137,16 @@ export default async (
// カスタム絵文字リアクションだったら絵文字情報も送る
const decodedReaction = decodeReaction(_reaction);
const emoji = await Emojis.findOne({
const emoji = await EmojiCache.fetch(
`${decodedReaction.name} ${decodedReaction.host}`,
() =>
Emojis.findOne({
where: {
name: decodedReaction.name,
host: decodedReaction.host ?? IsNull(),
},
select: ["name", "host", "originalUrl", "publicUrl"],
});
}),
);
publishNoteStream(note.id, "reacted", {
reaction: decodedReaction.reaction,