]> source.dussan.org Git - redmine.git/commitdiff
Prevent deadlocks by only locking the exact records we need to have locked (#25590).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Thu, 13 Apr 2017 12:10:03 +0000 (12:10 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Thu, 13 Apr 2017 12:10:03 +0000 (12:10 +0000)
Patch by Jens Kraemer.

git-svn-id: http://svn.redmine.org/redmine/trunk@16541 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/models/attachment.rb

index 26fe4a8b35f5a68aeb99bc8ec279202ad6f4c71f..89b9f8a7c7f20936a7e3c7f2a4f16b836aab7425 100644 (file)
@@ -417,27 +417,33 @@ class Attachment < ActiveRecord::Base
 
     reused = with_lock do
       if existing = Attachment
-                      .lock
                       .where(digest: self.digest, filesize: self.filesize)
                       .where('id <> ? and disk_filename <> ?',
                              self.id, self.disk_filename)
                       .first
+        existing.with_lock do
 
-        original_diskfile = self.diskfile
-        existing_diskfile = existing.diskfile
+          original_diskfile = self.diskfile
+          existing_diskfile = existing.diskfile
 
-        if File.readable?(original_diskfile) &&
-          File.readable?(existing_diskfile) &&
-          FileUtils.identical?(original_diskfile, existing_diskfile)
+          if File.readable?(original_diskfile) &&
+            File.readable?(existing_diskfile) &&
+            FileUtils.identical?(original_diskfile, existing_diskfile)
 
-          self.update_columns disk_directory: existing.disk_directory,
-                              disk_filename: existing.disk_filename
+            self.update_columns disk_directory: existing.disk_directory,
+                                disk_filename: existing.disk_filename
+          end
         end
       end
     end
     if reused
       File.delete(original_diskfile)
     end
+  rescue ActiveRecord::StatementInvalid, ActiveRecord::RecordNotFound
+    # Catch and ignore lock errors. It is not critical if deduplication does
+    # not happen, therefore we do not retry.
+    # with_lock throws ActiveRecord::RecordNotFound if the record isnt there
+    # anymore, thats why this is caught and ignored as well.
   end