Skip to content

Commit ba329d7

Browse files
gerrod3jobselko
authored andcommitted
Force content_ids requirement
fixes: #7466 https://redhat.atlassian.net/browse/PULP-577
1 parent 769313c commit ba329d7

11 files changed

Lines changed: 53 additions & 145 deletions

File tree

CHANGES/plugin_api/7466.removal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Made `content_ids` cache required with forceful migration and removed the `/pulp/api/v3/datarepair/7465/` endpoint. This **will** run a migration that could take a while if you haven't already run the datarepair endpoint.

docs/admin/guides/data-repair.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,6 @@ and recomputing the content counts. The repair operates within the current domai
109109
## Repair #7465: Populate missing Repository Version Caches
110110

111111
[Issue #7465](https://github.com/pulp/pulpcore/issues/7465) The repository version `content_ids` caches were added in [pulpcore 3.83](https://github.com/pulp/pulpcore/issues/5783) as a way to speed up the content set calculation performed anytime content is accessed from a repository. To ensure a smooth upgrade and maintain backwards compatibility, the new cache was only populated for newly created repository versions after 3.83. Starting in pulpcore 3.115 the cache will become required for all repository versions. This endpoint will spawn a task to populate any missing `content_ids` on all the repository versions in the task's domain.
112+
113+
!!! note
114+
This endpoint was removed in 3.115 with the upgrade migration forcefully populating any remaining empty cache.

pulpcore/app/checks.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -123,22 +123,3 @@ def check_artifact_checksums(app_configs, **kwargs):
123123
)
124124

125125
return messages
126-
127-
128-
@register(Tags.database)
129-
def check_repository_version_content_ids(app_configs, **kwargs):
130-
from pulpcore.app.models import RepositoryVersion
131-
132-
try:
133-
if RepositoryVersion.objects.filter(content_ids=None).exists():
134-
return [
135-
CheckWarning(
136-
"There are repository versions with no content_ids cache. Run "
137-
"'/pulp/api/v3/datarepair/7465/' to add missing content_ids cache to all "
138-
"repository versions. This will become an error in 3.115",
139-
id="pulpcore.W006",
140-
)
141-
]
142-
except Exception:
143-
pass
144-
return []
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Generated by Django 5.2.13 on 2026-06-08 21:54
2+
3+
import django.contrib.postgres.fields
4+
from django.db import migrations, models
5+
6+
7+
def populate_content_ids(apps, schema_editor):
8+
RepositoryVersion = apps.get_model('core', 'RepositoryVersion')
9+
RepositoryContent = apps.get_model('core', 'RepositoryContent')
10+
repo_versions = []
11+
for rv in RepositoryVersion.objects.filter(content_ids=None).iterator(chunk_size=2000):
12+
rv.content_ids = list(RepositoryContent.objects.filter(
13+
repository_id=rv.repository_id, version_added__number__lte=rv.number
14+
).exclude(version_removed__number__lte=rv.number).values_list("content_id", flat=True))
15+
repo_versions.append(rv)
16+
if len(repo_versions) >= 2000:
17+
RepositoryVersion.objects.bulk_update(repo_versions, ['content_ids'])
18+
repo_versions = []
19+
if repo_versions:
20+
RepositoryVersion.objects.bulk_update(repo_versions, ['content_ids'])
21+
22+
class Migration(migrations.Migration):
23+
24+
dependencies = [
25+
('core', '0151_upstreampulp_connect_timeout_and_more'),
26+
]
27+
28+
operations = [
29+
migrations.RunPython(populate_content_ids, reverse_code=migrations.RunPython.noop, elidable=True),
30+
migrations.AlterField(
31+
model_name='repositoryversion',
32+
name='content_ids',
33+
field=django.contrib.postgres.fields.ArrayField(base_field=models.UUIDField(), default=list, size=None),
34+
),
35+
]

pulpcore/app/models/repository.py

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ class RepositoryVersion(BaseModel):
942942
complete = models.BooleanField(db_index=True, default=False)
943943
base_version = models.ForeignKey("RepositoryVersion", null=True, on_delete=models.SET_NULL)
944944
info = models.JSONField(default=dict)
945-
content_ids = ArrayField(models.UUIDField(), default=None, null=True)
945+
content_ids = ArrayField(models.UUIDField(), default=list)
946946

947947
class Meta:
948948
default_related_name = "versions"
@@ -961,14 +961,6 @@ def _content_relationships(self):
961961
repository_id=self.repository_id, version_added__number__lte=self.number
962962
).exclude(version_removed__number__lte=self.number)
963963

964-
def _get_content_ids(self):
965-
"""
966-
Returns the content ids for a repository version
967-
"""
968-
if self.content_ids is not None:
969-
return self.content_ids
970-
return self._content_relationships().values_list("content_id", flat=True)
971-
972964
@hook(BEFORE_CREATE)
973965
def set_content_ids(self):
974966
"""
@@ -979,12 +971,7 @@ def set_content_ids(self):
979971
except self.DoesNotExist:
980972
pass
981973
else:
982-
if previous.content_ids is not None:
983-
self.content_ids = previous.content_ids
984-
if self.content_ids is None:
985-
self.content_ids = list(
986-
self._content_relationships().values_list("content_id", flat=True)
987-
)
974+
self.content_ids = previous.content_ids
988975

989976
def get_content(self, content_qs=None):
990977
"""
@@ -1009,8 +996,8 @@ def get_content(self, content_qs=None):
1009996
if content_qs is None:
1010997
content_qs = Content.objects
1011998

1012-
content_ids = self._get_content_ids()
1013-
if isinstance(content_ids, list) and len(content_ids) >= 65535:
999+
content_ids = self.content_ids
1000+
if len(content_ids) >= 65535:
10141001
# Workaround for PostgreSQL's limit on the number of parameters in a query
10151002
content_ids = (
10161003
RepositoryVersion.objects.filter(pk=self.pk)
@@ -1131,8 +1118,8 @@ def added(self, base_version=None):
11311118
if not base_version:
11321119
return Content.objects.filter(version_memberships__version_added=self)
11331120

1134-
return Content.objects.filter(pk__in=self._get_content_ids()).exclude(
1135-
pk__in=base_version._get_content_ids()
1121+
return Content.objects.filter(pk__in=self.content_ids).exclude(
1122+
pk__in=base_version.content_ids
11361123
)
11371124

11381125
def removed(self, base_version=None):
@@ -1146,8 +1133,8 @@ def removed(self, base_version=None):
11461133
if not base_version:
11471134
return Content.objects.filter(version_memberships__version_removed=self)
11481135

1149-
return Content.objects.filter(pk__in=base_version._get_content_ids()).exclude(
1150-
pk__in=self._get_content_ids()
1136+
return Content.objects.filter(pk__in=base_version.content_ids).exclude(
1137+
pk__in=self.content_ids
11511138
)
11521139

11531140
def contains(self, content):
@@ -1157,9 +1144,7 @@ def contains(self, content):
11571144
Returns:
11581145
bool: True if the repository version contains the content, False otherwise
11591146
"""
1160-
if self.content_ids is not None:
1161-
return content.pk in self.content_ids
1162-
return self.content.filter(pk=content.pk).exists()
1147+
return content.pk in self.content_ids
11631148

11641149
def add_content(self, content):
11651150
"""
@@ -1184,7 +1169,7 @@ def add_content(self, content):
11841169
)
11851170

11861171
repo_content = []
1187-
to_add = set(content.values_list("pk", flat=True)) - set(self._get_content_ids())
1172+
to_add = set(content.values_list("pk", flat=True)) - set(self.content_ids)
11881173
with transaction.atomic():
11891174
if to_add:
11901175
self.content_ids += list(to_add)
@@ -1234,7 +1219,7 @@ def remove_content(self, content):
12341219
.exclude(pulp_domain_id=get_domain_pk())
12351220
.exists()
12361221
)
1237-
content_ids = set(self._get_content_ids())
1222+
content_ids = set(self.content_ids)
12381223
to_remove = set(content.values_list("pk", flat=True))
12391224
with transaction.atomic():
12401225
if to_remove:

pulpcore/app/serializers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
RepositoryAddRemoveContentSerializer,
9999
RepositoryVersionSerializer,
100100
)
101-
from .repair import RepairSerializer, DataRepair7272Serializer, DataRepair7465Serializer
101+
from .repair import RepairSerializer, DataRepair7272Serializer
102102
from .reclaim import ReclaimSpaceSerializer
103103
from .task import (
104104
MinimalTaskSerializer,

pulpcore/app/serializers/repair.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,3 @@ class DataRepair7272Serializer(serializers.Serializer, ValidateFieldsMixin):
2626
"repair the detected issues."
2727
),
2828
)
29-
30-
31-
class DataRepair7465Serializer(serializers.Serializer, ValidateFieldsMixin):
32-
dry_run = fields.BooleanField(
33-
required=False,
34-
default=False,
35-
help_text=_(
36-
"If true, only report issues without fixing them. If false (default), "
37-
"repair the detected issues."
38-
),
39-
)

pulpcore/app/tasks/datarepair.py

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -112,61 +112,3 @@ def repair_7272(dry_run=False):
112112
f"Data repair operation for issue #7272 finished. ({number_broken} "
113113
f'repository versions fixed in domain "{domain.name}")'
114114
)
115-
116-
117-
def repair_7465(dry_run=False):
118-
"""
119-
Populates the content_ids cache for all repository versions.
120-
"""
121-
number_missing = 0
122-
domain = get_domain()
123-
124-
log.info(f'Performing datarepair for issue #7465 for domain "{domain.name}"')
125-
126-
repos = models.Repository.objects.filter(pulp_domain=domain)
127-
total_versions = models.RepositoryVersion.objects.filter(repository__in=repos).count()
128-
129-
with (
130-
ProgressReport(
131-
message="Repositories checked",
132-
code="repair.7465.repos_checked",
133-
total=repos.count(),
134-
) as repos_progress,
135-
ProgressReport(
136-
message="Repository versions checked",
137-
code="repair.7465.versions_checked",
138-
total=total_versions,
139-
) as versions_progress,
140-
ProgressReport(
141-
message="Repository versions fixed",
142-
code="repair.7465.versions_fixed",
143-
) as fixed_progress,
144-
):
145-
for repo in repos:
146-
for rv in models.RepositoryVersion.objects.filter(repository=repo):
147-
versions_progress.increment()
148-
if rv.content_ids is None:
149-
number_missing += 1
150-
if not dry_run:
151-
rv.content_ids = list(
152-
rv._content_relationships().values_list("content_id", flat=True)
153-
)
154-
rv.save()
155-
fixed_progress.increment()
156-
repos_progress.increment()
157-
158-
fixed_progress.total = number_missing
159-
160-
if not number_missing:
161-
log.info(f'Data repair operation for issue #7465 for domain "{domain.name}" finished. (OK)')
162-
else:
163-
if dry_run:
164-
log.info(
165-
f"Data repair operation for issue #7465 dry run finished. ({number_missing} "
166-
f'repository versions need fixing in domain "{domain.name}")'
167-
)
168-
else:
169-
log.info(
170-
f"Data repair operation for issue #7465 finished. ({number_missing} "
171-
f'repository versions fixed in domain "{domain.name}")'
172-
)

pulpcore/app/urls.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from pulpcore.app.apps import pulp_plugin_configs
1717
from pulpcore.app.views import (
1818
DataRepair7272View,
19-
DataRepair7465View,
2019
LivezView,
2120
OrphansView,
2221
PulpImporterImportCheckView,
@@ -156,7 +155,6 @@ class PulpDefaultRouter(routers.DefaultRouter):
156155
path("login/", LoginViewSet.as_view()),
157156
path("repair/", RepairView.as_view()),
158157
path("datarepair/7272/", DataRepair7272View.as_view()),
159-
path("datarepair/7465/", DataRepair7465View.as_view()),
160158
path(
161159
"orphans/cleanup/",
162160
OrphansCleanupViewset.as_view(actions={"post": "cleanup"}),

pulpcore/app/views/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ruff: noqa: F401
22
# isort: skip_file
3-
from .datarepair import DataRepair7272View, DataRepair7465View
3+
from .datarepair import DataRepair7272View
44
from .orphans import OrphansView
55
from .status import LivezView, StatusView
66
from .repair import RepairView

0 commit comments

Comments
 (0)