Skip to content

Commit 8c2f334

Browse files
authored
Sync versions: create new versions in bulk (#7382)
Currently we create version per version, this is calling the db n times (n the number of new versions). Bulk creation will produce only one call. To avoid having in memory all versions, we create them in batch as needed. https://docs.djangoproject.com/en/3.0/ref/models/querysets/#bulk-create
1 parent d1e08ef commit 8c2f334

File tree

1 file changed

+35
-9
lines changed

1 file changed

+35
-9
lines changed

readthedocs/api/v2/utils.py

+35-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def sync_versions_to_db(project, versions, type): # pylint: disable=redefined-b
2525
2626
- check if user has a ``stable`` / ``latest`` version and disable ours
2727
- update old versions with newer configs (identifier, type, machine)
28-
- create new versions that do not exist on DB
28+
- create new versions that do not exist on DB (in bulk)
2929
- it does not delete versions
3030
3131
:param project: project to update versions
@@ -40,6 +40,7 @@ def sync_versions_to_db(project, versions, type): # pylint: disable=redefined-b
4040
old_versions = dict(old_version_values)
4141

4242
# Add new versions
43+
versions_to_create = []
4344
added = set()
4445
has_user_stable = False
4546
has_user_latest = False
@@ -81,7 +82,7 @@ def sync_versions_to_db(project, versions, type): # pylint: disable=redefined-b
8182
identifier=version_id,
8283
type=type,
8384
machine=False,
84-
) # noqa
85+
)
8586

8687
log.info(
8788
'(Sync Versions) Updated Version: [%s=%s] ',
@@ -90,13 +91,12 @@ def sync_versions_to_db(project, versions, type): # pylint: disable=redefined-b
9091
)
9192
else:
9293
# New Version
93-
created_version = Version.objects.create(
94-
project=project,
95-
type=type,
96-
identifier=version_id,
97-
verbose_name=version_name,
98-
)
99-
added.add(created_version.slug)
94+
versions_to_create.append((version_id, version_name))
95+
96+
added.update(
97+
_create_versions_in_bulk(project, type, versions_to_create)
98+
)
99+
100100
if not has_user_stable:
101101
stable_version = (
102102
project.versions.filter(slug=STABLE, type=type).first()
@@ -120,6 +120,32 @@ def sync_versions_to_db(project, versions, type): # pylint: disable=redefined-b
120120
return added
121121

122122

123+
def _create_versions_in_bulk(project, type, versions):
124+
"""
125+
Create versions (tuple of version_id and version_name) in batch.
126+
127+
Returns the slug of all added versions.
128+
"""
129+
added = set()
130+
batch_size = 150
131+
objs = (
132+
Version(
133+
project=project,
134+
type=type,
135+
identifier=version_id,
136+
verbose_name=version_name,
137+
)
138+
for version_id, version_name in versions
139+
)
140+
while True:
141+
batch = list(itertools.islice(objs, batch_size))
142+
if not batch:
143+
break
144+
Version.objects.bulk_create(batch, batch_size)
145+
added.update(v.slug for v in batch)
146+
return added
147+
148+
123149
def _set_or_create_version(project, slug, version_id, verbose_name, type_):
124150
"""Search or create a version and set its machine attribute to false."""
125151
version = (project.versions.filter(slug=slug).first())

0 commit comments

Comments
 (0)