[RFC] Implement bzrlib.lock with CreateFile rather than LockFileEx on win32

Alexander Belchenko bialix at ukr.net
Tue Jun 16 21:39:59 BST 2009

Martin (gzlist) пишет:
> Thanks for the feedback.

Thanks to your attempt on this.

> 2009/6/16 Martin Pool <mbp at sourcefrog.net>:
>> 2009/6/10 Martin (gzlist) <gzlist at googlemail.com>:
>>> Questions:
>>> # Would a change along these lines be acceptable?
>> I think these a change along these lines would be fine, assuming it
>> pases tests (or doesn't cause any new failures.)  We should also
>> manually check interoperation with old versions, to make sure they
>> correctly exclude each other.
> Can test that just on the patch above. It basically works, the old
> two-step process gets Failed vs. Contention confused though, eg:
>>>> from bzrlib.lock import _pywin32_CreateFile_WriteLock, _w32c_WriteLock
>>>> a = _pywin32_CreateFile_WriteLock("/tmp.lock")
>>>> b = _w32c_WriteLock("/tmp.lock")
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "C:\bzr\bzr\lock_on_create\bzrlib\lock.py", line 426, in __init__
>     self._lock(filename, 'rb+', LOCK_EX + LOCK_NB)
>   File "C:\bzr\bzr\lock_on_create\bzrlib\lock.py", line 372, in _lock
>     self._open(filename, openmode)
>   File "C:\bzr\bzr\lock_on_create\bzrlib\lock.py", line 125, in _open
>     raise errors.LockFailed(self.filename, str(e))
> bzrlib.errors.LockFailed: Cannot lock C:/tmp.lock: [Errno 13]
> Permission denied: u'C:/tmp.lock'
>>>> a.unlock()
>>>> b = _w32c_WriteLock("/tmp.lock")
>>>> a = _pywin32_CreateFile_WriteLock("/tmp.lock")
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "C:\bzr\bzr\lock_on_create\bzrlib\lock.py", line 342, in __init__
>     os.O_RDWR, "rb+")
>   File "C:\bzr\bzr\lock_on_create\bzrlib\lock.py", line 325, in _open
>     raise errors.LockContention(filename, e)
> bzrlib.errors.LockContention: Could not acquire lock "/tmp.lock": (32,
> 'CreateFile', 'The process cannot access the file because it is being
> used by another process.')
>>> # Are there any expectations of the lock classes that aren't exercised in tests?
>> Possibly.  The main limitations seem to me to be:
>> 1. We don't have very good code for testing locking across different
>> unrelated processes, different threads, etc -- and the behaviour of
>> the locks we use there varies, which is bad.  Eventually we want to
>> get away from using OS file locks.
> I think you said something similar in Alexander's bug from 2007 that I
> linked. File locks don't seem to be going anywhere fast.
> Have been bothered before by unittest not doing multiprocess well, do
> you know of any work that's been done to get around that?

May be I don't understand what Martin Pool means but for me it's enough to run command in the
subprocess to force reliable inter-processes behaviour re locks (even on Linux).

So I'd suggest this.

>>> # Should the existing win32 classes be left in place for the moment at least?
>> I don't think so.  Do you?  If it turns out to be a problem we can
>> revert the change or (in the short term) people can downgrade.
> This seems fair, if new-over-old testing as per above is sufficient.
>>> # Would altering the design to avoid all the code duplication be warrented?
>> Feel free too, but maybe as a separate patch.
> Will look at as a later change as you suggest.
>>> # Are locks only taken on byte string filenames, or is unicode used as well?
>> I'm not sure tbh.  It can probably be either.
> Looking at it again, it seems _win32_realpath in bzrlib.osutils is
> effectively ensuring the filename is unicode (and that str input is an
> ascii, or it throws a UnicodeDecodeError).

Because tree could be placed in non-ascii directory I'd say it's most likely there is possible to
have unicode path to lock file.

>>> # How *are* you meant to do unicode exceptions in bazaar...
>> What do you mean?
> Sorry, I explained in a bit more detail in the message with the patch
> preceeding this one. Basically, windows gives error messages in the
> user's language, which pywin32 and ctypes expose as byte strings, that
> may well not be in the same encoding as the terminal/whatever bzr
> wants to write to the log. I wanted to know the right way to encode
> the message to get it to display correctly.
> Having looked at the bzrlib.errors code now though, it seems there is
> no right way. Even simple things will end up like:
> LockFailed(Unprintable exception LockFailed: dict={'msg': '', 'lock':
> u'somefile', 'why': 'O acesso \xe9 negado.'}, fmt='Cannot lock
> %(lock)s: %(why)s', error=<exceptions.UnicodeDecodeError instance at
> 0x00E33378>)
> Ensuring all params are unicode doesn't help much either, as the repr
> ends up as UTF-8 and thus mangled on the console. For
> non-ascii-superset languages, this means they're not going to be able
> to read the error messages at all.
> As it's now obvious this isn't a problem with an easy-but-undocumented
> solution, I'll ignore it for the moment.

Well, you can try to decode ErrorMessage with osutils.user_encoding() because this is most likely
the encoding of system messages. And fallback to repr() instead. This is really hard to do right.

More information about the bazaar mailing list