apenwarr-redo/redo/cmd_stamp.py
Avery Pennarun 61f3e4672e Workaround for completely broken file locking on Windows 10 WSL.
WSL (Windows Services for Linux) provides a Linux-kernel-compatible ABI
for userspace processes, but the current version doesn't not implement
fcntl() locks at all; it just always returns success.  See
https://github.com/Microsoft/WSL/issues/1927.

This causes us three kinds of problem:
  1. sqlite3 in WAL mode gives "OperationalError: locking protocol".
     1b. Other sqlite3 journal modes also don't work when used by
         multiple processes.
  2. redo parallelism doesn't work, because we can't prevent the same
     target from being build several times simultaneously.
  3. "redo-log -f" doesn't work, since it can't tell whether the log
     file it's tailing is "done" or not.

To fix #1, we switch the sqlite3 journal back to PERSIST instead of
WAL.  We originally changed to WAL in commit 5156feae9d to reduce
deadlocks on MacOS.  That was never adequately explained, but PERSIST
still acts weird on MacOS, so we'll only switch to PERSIST when we
detect that locking is definitely broken.  Sigh.

To (mostly) fix #2, we disable any -j value > 1 when locking is broken.
This prevents basic forms of parallelism, but doesn't stop you from
re-entrantly starting other instances of redo.  To fix that properly,
we need to switch to a different locking mechanism entirely, which is
tough in python.  flock() locks probably work, for example, but
python's locks lie and just use fcntl locks for those.

To fix #3, we always force --no-log mode when we find that locking is
broken.
2019-01-02 14:49:33 -05:00

66 lines
1.8 KiB
Python

"""redo-stamp: tell redo to use a checksum when considering this target."""
import sys, os
from . import env, logs, state
from .logs import debug2
def main():
if len(sys.argv) > 1:
sys.stderr.write('%s: no arguments expected.\n' % sys.argv[0])
sys.exit(1)
if os.isatty(0):
sys.stderr.write('%s: you must provide the data to stamp on stdin\n'
% sys.argv[0])
sys.exit(1)
env.inherit()
logs.setup(
tty=sys.stderr, parent_logs=env.v.LOG,
pretty=env.v.PRETTY, color=env.v.COLOR)
# hashlib is only available in python 2.5 or higher, but the 'sha'
# module produces a DeprecationWarning in python 2.6 or higher. We want
# to support python 2.4 and above without any stupid warnings, so let's
# try using hashlib first, and downgrade if it fails.
try:
import hashlib
except ImportError:
import sha
sh = sha.sha()
else:
sh = hashlib.sha1()
while 1:
b = os.read(0, 4096)
sh.update(b)
if not b:
break
csum = sh.hexdigest()
if not env.v.TARGET:
sys.exit(0)
me = os.path.join(env.v.STARTDIR,
os.path.join(env.v.PWD, env.v.TARGET))
f = state.File(name=me)
changed = (csum != f.csum)
debug2('%s: old = %s\n' % (f.name, f.csum))
debug2('%s: sum = %s (%s)\n' % (f.name, csum,
changed and 'changed' or 'unchanged'))
f.is_generated = True
f.is_override = False
f.failed_runid = None
if changed:
f.set_changed() # update_stamp might skip this if mtime is identical
f.csum = csum
else:
# unchanged
f.set_checked()
f.save()
state.commit()
if __name__ == '__main__':
main()