Merge ~twom/launchpad:fix-race-condition-in-contents-files into launchpad:master

Proposed by Tom Wardill
Status: Merged
Approved by: Tom Wardill
Approved revision: e2859a79ac0c3c4ee2a2db20269df6fd7058b20a
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~twom/launchpad:fix-race-condition-in-contents-files
Merge into: launchpad:master
Diff against target: 72 lines (+21/-5)
1 file modified
lib/lp/archivepublisher/model/ftparchive.py (+21/-5)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+374930@code.launchpad.net

Commit message

Fix race conditions in contents files

Description of the change

A race condition between generateOverrides and listFiles meant that the files were being read as they were being written, occasionally leading to the contents being empty.

This MP changes the file writing behaviour of both methods to write to a '.new' file, then use rename to move the file into the final location. This should be an atomic operation and prevent the zero length files from occurring.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve
e2859a7... by Tom Wardill

Remove extra new line

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 219515b..39e7d40 100644
3--- a/lib/lp/archivepublisher/model/ftparchive.py
4+++ b/lib/lp/archivepublisher/model/ftparchive.py
5@@ -480,13 +480,17 @@ class FTPArchiveHandler:
6 "override.%s.%s" % (suite, component))
7 ef_override = os.path.join(self._config.overrideroot,
8 "override.%s.extra.%s" % (suite, component))
9+ ef_override_new = "{}.new".format(ef_override)
10+ # Create the files as .new and then move into place to prevent
11+ # race conditions with other processes handling these files
12+ main_override_new = "{}.new".format(main_override)
13 source_override = os.path.join(self._config.overrideroot,
14 "override.%s.%s.src" %
15 (suite, component))
16
17 # Start to write the files out
18- ef = open(ef_override, "w")
19- f = open(main_override, "w")
20+ ef = open(ef_override_new, "w")
21+ f = open(main_override_new, "w")
22 basic_override_seen = set()
23 for (package_arch, priority, section,
24 phased_update_percentage) in bin_overrides:
25@@ -512,6 +516,8 @@ class FTPArchiveHandler:
26 str(phased_update_percentage)]))
27 ef.write("\n")
28 f.close()
29+ # Move into place
30+ os.rename(main_override_new, main_override)
31
32 if os.path.exists(extra_extra_overrides):
33 # XXX kiko 2006-08-24: This is untested.
34@@ -533,13 +539,18 @@ class FTPArchiveHandler:
35 # XXX: dsilvers 2006-08-23 bug=3900: As above,
36 # this needs to be integrated into the database at some point.
37 ef.close()
38+ # Move into place
39+ os.rename(ef_override_new, ef_override)
40
41 def _outputSimpleOverrides(filename, overrides):
42- sf = open(filename, "w")
43+ # Write to a different file, then move into place
44+ filename_new = "{}.new".format(filename)
45+ sf = open(filename_new, "w")
46 for tup in overrides:
47 sf.write("\t".join(tup))
48 sf.write("\n")
49 sf.close()
50+ os.rename(filename_new, filename)
51
52 _outputSimpleOverrides(source_override, src_overrides)
53
54@@ -716,11 +727,16 @@ class FTPArchiveHandler:
55 self.log.debug(
56 "Writing %s file list for %s/%s/%s" % (
57 desc, dr_pocketed, component, arch))
58- path = os.path.join(self._config.overrideroot, filename)
59- with open(path, "w") as f:
60+ # Prevent race conditions with other processes handling these
61+ # files, create as .new and then move into place
62+ new_path = os.path.join(
63+ self._config.overrideroot, "{}.new".format(filename))
64+ final_path = os.path.join(self._config.overrideroot, filename)
65+ with open(new_path, 'w') as f:
66 files[subcomp].sort(key=package_name)
67 f.write("\n".join(files[subcomp]))
68 f.write("\n")
69+ os.rename(new_path, final_path)
70
71 #
72 # Config Generation

Subscribers

People subscribed via source and target branches

to status/vote changes: