From 6554ea0abb31a15684e08c14bc6589a273cc19d6 Mon Sep 17 00:00:00 2001 From: Alex Olshansky Date: Wed, 19 Jan 2022 16:48:40 +0100 Subject: [PATCH] short-links: Wrap short_id creation into a transaction --- app/support/DbAdapter/posts.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/app/support/DbAdapter/posts.js b/app/support/DbAdapter/posts.js index df04ac670..d4ef93f76 100644 --- a/app/support/DbAdapter/posts.js +++ b/app/support/DbAdapter/posts.js @@ -25,10 +25,19 @@ const postsTrait = (superClass) => // https://github.com/knex/knex/issues/2622 toTSVector(preparedPayload.body).replace(/\?/g, '\\?'), ); - const [postId] = await this.database('posts').returning('uid').insert(preparedPayload); - // Create a short Id for this post - await this.createPostShortId(postId); + const postId = await this.database.transaction(async (trx) => { + // Lock post_short_ids table to prevent any updates + await trx.raw('lock table post_short_ids in share row exclusive mode'); + + // Create post + const [postId] = await trx('posts').insert(preparedPayload).returning('uid'); + + // Create a short ID for this post + await this.createPostShortId(trx, postId); + + return postId; + }); // Update backlinks in the post body await this.updateBacklinks(payload.body, postId); @@ -408,23 +417,23 @@ const postsTrait = (superClass) => return this.getUsersByIds(adminIds); } - async createPostShortId(longId) { + async createPostShortId(trx, longId) { let length = config.postShortIds.initialLength; for (; ; length++) { // eslint-disable-next-line no-await-in-loop - if (await this.createPostShortIdForLength(longId, length)) { + if (await this.createPostShortIdForLength(trx, longId, length)) { return; } } } - async createPostShortIdForLength(longId, length) { + async createPostShortIdForLength(trx, longId, length) { for (let i = 0; i < config.postShortIds.maxAttempts; i++) { const shortId = this.getDecentRandomString(length); // eslint-disable-next-line no-await-in-loop - const res = await this.database('post_short_ids') + const res = await trx('post_short_ids') .insert({ short_id: shortId, long_id: longId }) .returning('short_id');