Optimize SQL query that fetch actor outbox
authorChocobozzz <me@florianbigard.com>
Thu, 18 Jan 2018 14:22:36 +0000 (15:22 +0100)
committerChocobozzz <me@florianbigard.com>
Thu, 18 Jan 2018 15:43:26 +0000 (16:43 +0100)
server/lib/activitypub/actor.ts
server/models/video/video.ts
server/tests/api/server/follows.ts
server/tests/api/server/handle-down.ts

index a39b4e137b008a013c1b945ee17b084cb63335d3..7494aadbb84b7dca0c2e9ce7a92804ef43813f2b 100644 (file)
@@ -212,7 +212,13 @@ function saveActorAndServerAndModelIfNotExist (
 
     // Force the actor creation, sometimes Sequelize skips the save() when it thinks the instance already exists
     // (which could be false in a retried query)
-    const actorCreated = await ActorModel.create(actor.toJSON(), { transaction: t })
+    const [ actorCreated ] = await ActorModel.findOrCreate({
+      defaults: actor.toJSON(),
+      where: {
+        url: actor.url
+      },
+      transaction: t
+    })
 
     if (actorCreated.type === 'Person' || actorCreated.type === 'Application') {
       const account = await saveAccount(actorCreated, result, t)
@@ -284,24 +290,36 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu
   }
 }
 
-function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) {
-  const account = new AccountModel({
-    name: result.name,
-    actorId: actor.id
+async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) {
+  const [ accountCreated ] = await AccountModel.findOrCreate({
+    defaults: {
+      name: result.name,
+      actorId: actor.id
+    },
+    where: {
+      actorId: actor.id
+    },
+    transaction: t
   })
 
-  return account.save({ transaction: t })
+  return accountCreated
 }
 
 async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResult, ownerActor: ActorModel, t: Transaction) {
-  const videoChannel = new VideoChannelModel({
-    name: result.name,
-    description: result.summary,
-    actorId: actor.id,
-    accountId: ownerActor.Account.id
+  const [ videoChannelCreated ] = await VideoChannelModel.findOrCreate({
+    defaults: {
+      name: result.name,
+      description: result.summary,
+      actorId: actor.id,
+      accountId: ownerActor.Account.id
+    },
+    where: {
+      actorId: actor.id
+    },
+    transaction: t
   })
 
-  return videoChannel.save({ transaction: t })
+  return videoChannelCreated
 }
 
 async function refreshActorIfNeeded (actor: ActorModel) {
index 0d115367f81e27b5b7f569330784e3ecc00c47fd..7af68b20bbdfa66f4e3e3bc040115ecdb32af61a 100644 (file)
@@ -459,7 +459,8 @@ export class VideoModel extends Model<VideoModel> {
       },
       include: [
         {
-          model: VideoShareModel,
+          attributes: [ 'id' ],
+          model: VideoShareModel.unscoped(),
           required: false,
           where: {
             [Sequelize.Op.and]: [
@@ -475,28 +476,65 @@ export class VideoModel extends Model<VideoModel> {
           },
           include: [
             {
-              model: ActorModel,
-              required: true
+              attributes: [ 'id', 'url' ],
+              model: ActorModel.unscoped()
             }
           ]
         },
         {
-          model: VideoChannelModel,
+          model: VideoChannelModel.unscoped(),
           required: true,
           include: [
             {
-              model: AccountModel,
+              attributes: [ 'name' ],
+              model: AccountModel.unscoped(),
+              required: true,
+              include: [
+                {
+                  attributes: [ 'id', 'url' ],
+                  model: ActorModel.unscoped(),
+                  required: true
+                }
+              ]
+            },
+            {
+              attributes: [ 'id', 'url' ],
+              model: ActorModel.unscoped(),
               required: true
             }
           ]
         },
         {
+          attributes: [ 'type' ],
           model: AccountVideoRateModel,
-          include: [ AccountModel ]
+          required: false,
+          include: [
+            {
+              attributes: [ 'id' ],
+              model: AccountModel.unscoped(),
+              include: [
+                {
+                  attributes: [ 'url' ],
+                  model: ActorModel.unscoped(),
+                  include: [
+                    {
+                      attributes: [ 'host' ],
+                      model: ServerModel,
+                      required: false
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        },
+        {
+          attributes: [ 'url' ],
+          model: VideoCommentModel,
+          required: false
         },
         VideoFileModel,
-        TagModel,
-        VideoCommentModel
+        TagModel
       ]
     }
 
index c0115e534c6db7e425895404a69573f89272563c..b26af1a169dd34cb11fd42342c42032ce7d485a8 100644 (file)
@@ -4,7 +4,7 @@ import * as chai from 'chai'
 import 'mocha'
 import { Video, VideoPrivacy } from '../../../../shared/models/videos'
 import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
-import { checkVideoFilesWereRemoved, completeVideoCheck } from '../../utils'
+import { completeVideoCheck } from '../../utils'
 
 import {
   flushAndRunMultipleServers, flushTests, getVideosList, killallServers, ServerInfo, setAccessTokensToServers, uploadVideo,
@@ -353,8 +353,6 @@ describe('Test follows', function () {
 
       let res = await getVideosList(servers[ 0 ].url)
       expect(res.body.total).to.equal(1)
-
-      await checkVideoFilesWereRemoved(video4.uuid, servers[0].serverNumber)
     })
 
   })
index 6ca8cfb648dcc80718f576b5b9f3b937dc9dfc7b..e99e517e4e5dd4fa5186e802110c022b390a7775 100644 (file)
@@ -187,10 +187,6 @@ describe('Test handle downs', function () {
 
     await wait(5000)
 
-    const res = await getVideosList(servers[1].url)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data).to.have.lengthOf(2)
-
     const resVideo = await getVideo(servers[1].url, videos[0].uuid)
     expect(resVideo.body).not.to.be.undefined