diff options
author | Stan Hu <stanhu@gmail.com> | 2019-01-14 16:08:28 -0800 |
---|---|---|
committer | Stan Hu <stanhu@gmail.com> | 2019-01-14 21:17:40 -0800 |
commit | bcdb5a0a2d62caa685c32c5d1a4453bd5926b5b1 (patch) | |
tree | 73053901d8d0d565d949e8359c2d03f1de65bffc /app/uploaders | |
parent | 0e510780a15955b06445fb4c440230151da9ae93 (diff) | |
download | gitlab-ce-bcdb5a0a2d62caa685c32c5d1a4453bd5926b5b1.tar.gz |
Fix failing MySQL spec due to deadlock condition
`spec/features/uploads/user_uploads_file_to_note_spec.rb` was failing in
master because MySQL detected a deadlock when a DELETE and INSERT for
the same indexed item occurred within a transaction in the `uploads`
table. Due to InnoDB's next-key locking algorithm
(innodb_locks_unsafe_for_binlog in
https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html), InnoDB
sets an exclusive lock for any of the indexed records it encounters, so
the INSERT will fail until the DELETE is committed.
To fix this, we just disable the transaction for MySQL and keep
it for PostgreSQL.
Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/55161
Diffstat (limited to 'app/uploaders')
-rw-r--r-- | app/uploaders/records_uploads.rb | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/app/uploaders/records_uploads.rb b/app/uploaders/records_uploads.rb index 0efca895a50..9a243e07936 100644 --- a/app/uploaders/records_uploads.rb +++ b/app/uploaders/records_uploads.rb @@ -23,13 +23,23 @@ module RecordsUploads return unless model return unless file && file.exists? - Upload.transaction do - uploads.where(path: upload_path).delete_all - upload.delete if upload - - self.upload = build_upload.tap(&:save!) + # MySQL InnoDB may encounter a deadlock if a deletion and an + # insert is in the same transaction due to its next-key locking + # algorithm, so we need to skip the transaction. + # https://gitlab.com/gitlab-org/gitlab-ce/issues/55161#note_131556351 + if Gitlab::Database.mysql? + readd_upload + else + Upload.transaction { readd_upload } end end + + def readd_upload + uploads.where(path: upload_path).delete_all + upload.delete if upload + + self.upload = build_upload.tap(&:save!) + end # rubocop: enable CodeReuse/ActiveRecord def upload_path |