Browse Source

builder.py: atomically replace the log for a given target.

Previously we were truncating the log if it existed.  This would cause
redo-log to produce invalid output if you had the following (admittedly
rare) sequence in a single session:
- start building X
- redo-log starts showing the log for X
- finish building X
- redo-log has not finished showing the log for X yet
- start building X again for some reason
- redo-log sees a truncated logfile.

Now, redo-log can finish reading the original file (which no longer has
a filename since it was overwritten) while the new file is being
created.
experimental/dockrepo
Avery Pennarun 2 years ago
parent
commit
63230a1ae3
2 changed files with 14 additions and 4 deletions
  1. +1
    -1
      bin/all.do
  2. +13
    -3
      redo/builder.py

+ 1
- 1
bin/all.do View File

@ -1,3 +1,3 @@
exec >&2
redo-ifchange ../redo/version/all ../redo/py list redo-sh
redo-ifchange ../redo/version/all ../redo/py ../redo/sh list
xargs redo-ifchange <list

+ 13
- 3
redo/builder.py View File

@ -229,10 +229,20 @@ class _BuildJob(object):
firstline = open(os.path.join(dodir, dofile)).readline().strip()
if firstline.startswith('#!/'):
argv[0:2] = firstline[2:].split(' ')
# make sure to create the logfile *before* writing the meta() about it.
# that way redo-log won't trace into an obsolete logfile.
# make sure to create the logfile *before* writing the meta() about
# it. that way redo-log won't trace into an obsolete logfile.
#
# We open a temp file and atomically rename it into place here.
# This guarantees that redo-log will never experience a file that
# gets truncated halfway through reading (eg. if we build the same
# target more than once in a run). Similarly, we don't want to
# actually unlink() the file in case redo-log is about to start
# reading a previous instance created during this session. It
# should always see either the old or new instance.
if env.v.LOG:
open(state.logname(self.sf.id), 'w')
lfd, lfname = tempfile.mkstemp(prefix='redo.', suffix='.log.tmp')
os.fdopen(lfd, 'w')
os.rename(lfname, state.logname(self.sf.id))
dof = state.File(name=os.path.join(dodir, dofile))
dof.set_static()
dof.save()


Loading…
Cancel
Save