From 544b968f4caf74f03ac67a218a59b96ddaa57099 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 12 2023 12:40:35 +0000 Subject: [PATCH 1/3] use table lock while adding new external rpms PR #794 introduced savepoint-based solution for parallel addition of external rpms. In some usecases there could be a lot of external rpms being added, so potential for deadlock is much higher than before. Locking the table seems to be a bit expensive but SHARE ROW EXCLUSIVE should be a working compromise (anyone not writing to the table has still read access). Related: https://pagure.io/koji/issue/3637 --- diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index 1209cca..ea5c4bd 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -7162,6 +7162,9 @@ def add_external_rpm(rpminfo, external_repo, strict=True): # [!] Calling function should perform access checks + # lock table because of concurrent inserts + _dml('LOCK TABLE rpminfo IN SHARE ROW EXCLUSIVE MODE', {}) + # sanity check rpminfo dtypes = ( ('name', str), @@ -7208,17 +7211,7 @@ def add_external_rpm(rpminfo, external_repo, strict=True): data['build_id'] = None data['buildroot_id'] = None insert = InsertProcessor('rpminfo', data=data) - savepoint = Savepoint('pre_insert') - try: - insert.execute() - except Exception: - # if this failed, it likely duplicates one just inserted - # see: https://pagure.io/koji/issue/788 - savepoint.rollback() - previous = check_dup() - if previous: - return previous - raise + insert.execute() return get_rpm(data['id']) From 67cfe5bdd4b685752436567241475123dad08ad5 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 12 2023 12:40:35 +0000 Subject: [PATCH 2/3] Revert "use table lock while adding new external rpms" This reverts commit 9fca1283994c948b28f14884056e802b58a58048. --- diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py index ea5c4bd..1209cca 100644 --- a/kojihub/kojihub.py +++ b/kojihub/kojihub.py @@ -7162,9 +7162,6 @@ def add_external_rpm(rpminfo, external_repo, strict=True): # [!] Calling function should perform access checks - # lock table because of concurrent inserts - _dml('LOCK TABLE rpminfo IN SHARE ROW EXCLUSIVE MODE', {}) - # sanity check rpminfo dtypes = ( ('name', str), @@ -7211,7 +7208,17 @@ def add_external_rpm(rpminfo, external_repo, strict=True): data['build_id'] = None data['buildroot_id'] = None insert = InsertProcessor('rpminfo', data=data) - insert.execute() + savepoint = Savepoint('pre_insert') + try: + insert.execute() + except Exception: + # if this failed, it likely duplicates one just inserted + # see: https://pagure.io/koji/issue/788 + savepoint.rollback() + previous = check_dup() + if previous: + return previous + raise return get_rpm(data['id']) From 453e3de28b3f0643eb15d3d589c21b52dfaa86de Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Jun 12 2023 12:44:19 +0000 Subject: [PATCH 3/3] Sort kiwi package output before import Related: https://pagure.io/koji/issue/3637 --- diff --git a/plugins/builder/kiwi.py b/plugins/builder/kiwi.py index e1c7a0a..492c2c1 100644 --- a/plugins/builder/kiwi.py +++ b/plugins/builder/kiwi.py @@ -275,7 +275,9 @@ class KiwiCreateImageTask(BaseBuildTask): found = True if not found: raise koji.LiveCDError('No repos found in yum cache!') - return list(hdrlist.values()) + # Sort on return deterministically (key is ~nevra) to not cause race conditions on import + return sorted(hdrlist.values(), + key=lambda x: {x['name'], x['epoch'], x['version'], x['release'], x['arch']}) def getImagePackages(self, result): """Proper handler for getting rpminfo from result list, @@ -299,7 +301,9 @@ class KiwiCreateImageTask(BaseBuildTask): 'buildtime': 0, }) - return hdrlist + # Sort on return deterministically (key is ~nevra) to not cause race conditions on import + return sorted(hdrlist, + key=lambda x: {x['name'], x['epoch'], x['version'], x['release'], x['arch']}) def handler(self, name, version, release, arch, target_info, build_tag, repo_info,