Merge ~cjwatson/launchpad:ftparchive-avoid-empty-overrides into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 25ce0c1d87878ef4fb7e5f0ae2e971130f43c525
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:ftparchive-avoid-empty-overrides
Merge into: launchpad:master
Diff against target: 107 lines (+44/-8)
2 files modified
lib/lp/archivepublisher/model/ftparchive.py (+11/-7)
lib/lp/archivepublisher/tests/test_ftparchive.py (+33/-1)
Reviewer Review Type Date Requested Status
Cristian Gonzalez (community) Approve
Review via email: mp+399940@code.launchpad.net

Commit message

Don't overwrite existing files in createEmptyPocketRequests

Description of the change

The job of `FTPArchive.createEmptyPocketRequests` is to make sure that override and file list files for suites/components that we're publishing exist even if they're going to end up empty. It did this by making them empty, which was OK when nothing was reading from those files in parallel. However, that hasn't been true for some time due to Contents file generation, and the current implementation means that it's possible for Contents file generation to see temporarily-empty versions of these files and thus generate empty Contents files.

To fix this, only create these files if they don't already exist. This should complete the fix in https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/374930.

To post a comment you must log in.
Revision history for this message
Cristian Gonzalez (cristiangsp) wrote :

Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/archivepublisher/model/ftparchive.py b/lib/lp/archivepublisher/model/ftparchive.py
2index 3203771..a13269e 100644
3--- a/lib/lp/archivepublisher/model/ftparchive.py
4+++ b/lib/lp/archivepublisher/model/ftparchive.py
5@@ -1,4 +1,4 @@
6-# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
7+# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9
10 from collections import defaultdict
11@@ -242,7 +242,7 @@ class FTPArchiveHandler:
12 """Creates empty files for a release pocket and distroseries"""
13 suite = distroseries.getSuite(pocket)
14
15- # Create empty override lists.
16+ # Create empty override lists if they don't already exist.
17 needed_paths = [
18 (comp,),
19 ("extra", comp),
20@@ -252,15 +252,19 @@ class FTPArchiveHandler:
21 needed_paths.append((comp, sub_comp))
22
23 for path in needed_paths:
24- write_file(os.path.join(
25+ full_path = os.path.join(
26 self._config.overrideroot,
27- ".".join(("override", suite) + path)), b"")
28+ ".".join(("override", suite) + path))
29+ if not os.path.exists(full_path):
30+ write_file(full_path, b"")
31
32- # Create empty file lists.
33+ # Create empty file lists if they don't already exist.
34 def touch_list(*parts):
35- write_file(os.path.join(
36+ full_path = os.path.join(
37 self._config.overrideroot,
38- "_".join((suite, ) + parts)), b"")
39+ "_".join((suite, ) + parts))
40+ if not os.path.exists(full_path):
41+ write_file(full_path, b"")
42 touch_list(comp, "source")
43
44 arch_tags = [
45diff --git a/lib/lp/archivepublisher/tests/test_ftparchive.py b/lib/lp/archivepublisher/tests/test_ftparchive.py
46index 7209f53..3a9665a 100755
47--- a/lib/lp/archivepublisher/tests/test_ftparchive.py
48+++ b/lib/lp/archivepublisher/tests/test_ftparchive.py
49@@ -1,4 +1,4 @@
50-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
51+# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
52 # GNU Affero General Public License version 3 (see the file LICENSE).
53
54 """Tests for ftparchive.py"""
55@@ -22,6 +22,7 @@ from debian.deb822 import (
56 )
57 from testtools.matchers import (
58 Equals,
59+ FileContains,
60 LessThan,
61 MatchesListwise,
62 )
63@@ -42,6 +43,7 @@ from lp.services.log.logger import (
64 BufferLogger,
65 DevNullLogger,
66 )
67+from lp.services.osutils import write_file
68 from lp.soyuz.enums import (
69 BinaryPackageFormat,
70 IndexCompressionType,
71@@ -192,6 +194,36 @@ class TestFTPArchive(TestCaseWithFactory):
72 [('tiny', 'tiny_0.1_i386.deb', component, 'binary-i386')])
73 fa.publishFileLists('hoary-test', source_files, binary_files)
74
75+ def test_createEmptyPocketRequests_preserves_existing(self):
76+ # createEmptyPocketRequests leaves existing override and file list
77+ # files alone, in order to avoid race conditions with other
78+ # processes (e.g. generate-contents-files) reading those files in
79+ # parallel.
80+ publisher = Publisher(
81+ self._logger, self._config, self._dp, self._archive)
82+ fa = FTPArchiveHandler(
83+ self._logger, self._config, self._dp, self._distribution,
84+ publisher)
85+ lists = (
86+ 'hoary-test-updates_main_source',
87+ 'hoary-test-updates_main_binary-i386',
88+ 'hoary-test-updates_main_debian-installer_binary-i386',
89+ 'override.hoary-test-updates.main',
90+ 'override.hoary-test-updates.extra.main',
91+ 'override.hoary-test-updates.main.src',
92+ )
93+ for listname in lists:
94+ write_file(
95+ os.path.join(self._config.overrideroot, listname),
96+ b'previous contents\n')
97+
98+ fa.createEmptyPocketRequests(fullpublish=True)
99+
100+ for listname in lists:
101+ self.assertThat(
102+ os.path.join(self._config.overrideroot, listname),
103+ FileContains('previous contents\n'))
104+
105 def test_getSourcesForOverrides(self):
106 # getSourcesForOverrides returns a list of tuples containing:
107 # (sourcename, component, section)

Subscribers

People subscribed via source and target branches

to status/vote changes: