Project

Profile

Help

Issue #5982

closed

Race condition in RepositoryVersion.new_version()

Added by osapryki almost 5 years ago. Updated about 4 years ago.

Status:
CLOSED - WORKSFORME
Priority:
Normal
Assignee:
-
Category:
-
Sprint/Milestone:
-
Start date:
Due date:
Estimated time:
Severity:
2. Medium
Version:
Platform Release:
OS:
Triaged:
Yes
Groomed:
No
Sprint Candidate:
No
Tags:
Sprint:
Quarter:

Description

If `RepositoryVersion.new_version` is executed at the same time in two parallel transactions, one of transactions may fail with unique constraint error:

duplicate key value violates unique constraint "pulp_app_repositoryversion_repository_id_number_07cb5788_uniq" DETAIL: Key (repository_id, number)=(1, 735) already exists.

This is caused because of race condition possible in `RepositoryVersion.new_version()` call:

SELECT last_version FROM pulp_app_repository WHERE id = 1
 last_version
--------------
          21

TRANSACTION 1       TRANSACTION 2
=============       =============
BEGIN;
-----------------------------------------------------------
                    BEGIN;
-----------------------------------------------------------
INSERT INTO pulp_app_repositoryversion
(repository_id, number) VALUES (1, 22)
# NOTE: number = int(self.last_version) + 1;
-----------------------------------------------------------
UPDATE pulp_app_repository
SET last_version = 22;
-----------------------------------------------------------
                    INSERT INTO pulp_app_repositoryversion
                    (repository_id, number) VALUES (1, 22)
                    # NOTE: number = int(self.last_version) + 1;
-----------------------------------------------------------
                    UPDATE pulp_app_repository
                    SET last_version = 22;
-----------------------------------------------------------
COMMIT;
# NOTE: OK
-----------------------------------------------------------
                    COMMIT;
                    # NOTE: uplicate key value violates unique
                    # constraint
-----------------------------------------------------------

Solution:

You should lock repository record to perform `last_version` increment and update (e.g. do SELECT FOR UPDATE before incrementing last_version counter and creating a new version).

Actions #1

Updated by bmbouter almost 5 years ago

I want to share some info on Pulp's tasking system. Pulp's tasking system provides a serialization of tasks based on locks. In the case of new_version, e.g. it's typically called from add_and_remove here. That is dispatched with the lock on repository itself second param here which causes add_and_remove operations to be serialized.

Improving the code to have fewer race conditions sounds good though, especially if plugin writers want to create new versions in the viewset. Do plugins want to create new_version in the viewsets?

Actions #2

Updated by fao89 almost 5 years ago

  • Triaged changed from No to Yes
Actions #3

Updated by dkliban@redhat.com about 4 years ago

  • Status changed from NEW to CLOSED - WORKSFORME

Repository Versions should be created inside of tasks so that the work is serialized.

Also available in: Atom PDF