From 15f6f095b1d46306c0747daf29d9381355ee1146 Mon Sep 17 00:00:00 2001 From: Alan Rominger Date: Thu, 21 Sep 2023 14:27:04 -0400 Subject: [PATCH] AAP-15927 Use ATTACH PARTITION to avoid exclusive table lock for events (#14433) --- awx/main/utils/common.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index 1e134b46f82d..f653b18e0c70 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -23,7 +23,7 @@ from django.utils.dateparse import parse_datetime from django.utils.translation import gettext_lazy as _ from django.utils.functional import cached_property -from django.db import connection, transaction, ProgrammingError +from django.db import connection, transaction, ProgrammingError, IntegrityError from django.db.models.fields.related import ForeignObjectRel, ManyToManyField from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor, ManyToManyDescriptor from django.db.models.query import QuerySet @@ -1164,13 +1164,23 @@ def create_partition(tblname, start=None): try: with transaction.atomic(): with connection.cursor() as cursor: + r_tuples = cursor.execute(f"SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = '{tblname}_{partition_label}');") + for row in r_tuples: # should only have 1 + for val in row: # should only have 1 + if val is True: + logger.debug(f'Event partition table {tblname}_{partition_label} already exists') + return + cursor.execute( - f'CREATE TABLE IF NOT EXISTS {tblname}_{partition_label} ' - f'PARTITION OF {tblname} ' - f'FOR VALUES FROM (\'{start_timestamp}\') to (\'{end_timestamp}\');' + f'CREATE TABLE {tblname}_{partition_label} (LIKE {tblname} INCLUDING DEFAULTS INCLUDING CONSTRAINTS); ' + f'ALTER TABLE {tblname} ATTACH PARTITION {tblname}_{partition_label} ' + f'FOR VALUES FROM (\'{start_timestamp}\') TO (\'{end_timestamp}\');' ) - except ProgrammingError as e: - logger.debug(f'Caught known error due to existing partition: {e}') + except (ProgrammingError, IntegrityError) as e: + if 'already exists' in str(e): + logger.info(f'Caught known error due to partition creation race: {e}') + else: + raise def cleanup_new_process(func):