Commit Graph

70 Commits

Author SHA1 Message Date
FUJIWARA Katsunori
8f34219d1a lock: avoid unintentional lock acquisition at failure of readlock
Acquiring lock by vfs.makelock() and getting lock holder (aka
"locker") information by vfs.readlock() aren't atomic action.
Therefore, failure of the former doesn't ensure success of the latter.

Before this patch, lock is unintentionally acquired, if ENOENT
causes failure of vfs.readlock() while 5 times retrying, because
lock._trylock() returns to caller silently after retrying, and
lock.lock() assumes that lock._trylock() returns successfully only if
lock is acquired.

In this case, lock symlink (or file) isn't created, even though lock
is treated as acquired in memory.

To avoid this issue, this patch makes lock._trylock() raise
LockHeld(EAGAIN) at the end of it, if lock isn't acquired while
retrying.

An empty "locker" meaning "busy for frequent lock/unlock by many
processes" might appear in an abortion message, if lock acquisition
fails. Therefore, this patch also does:

  - use '%r' to increase visibility of "locker", even if it is empty
  - show hint message to explain what empty "locker" means
2017-05-01 19:59:13 +09:00
FUJIWARA Katsunori
cb1cfe7f12 lock: avoid unintentional lock acquisition at failure of readlock
Acquiring lock by vfs.makelock() and getting lock holder (aka
"locker") information by vfs.readlock() aren't atomic action.
Therefore, failure of the former doesn't ensure success of the latter.

Before this patch, lock is unintentionally acquired, if
self.parentlock is None (this is default value), and lock._readlock()
returns None for ENOENT at vfs.readlock(), because these None are
recognized as equal to each other.

In this case, lock symlink (or file) isn't created, even though lock
is treated as acquired in memory.

To avoid this issue, this patch retries lock acquisition immediately,
if lock._readlock() returns None "locker".

This issue will be covered by a test added in subsequent patch,
because simple emulation of ENOENT at vfs.readlock() easily causes
another issue.  "raising ENOENT only at the first vfs.readlock()
invocation" is too complicated for unit test, IMHO.
2017-05-01 19:58:52 +09:00
Yuya Nishihara
1aa2b14401 lock: do not encode result of gethostname on Python 2
If a hostname contained non-ascii character, str.encode() would first try
to decode it to a unicode and raise UnicodeDecodeError.
2017-03-12 16:26:34 -07:00
Augie Fackler
3c69b88530 lock: encode result of gethostname into a bytestring 2017-03-12 03:28:50 -04:00
Augie Fackler
b4f8ffef60 lock: use %d to format integer into a bytestring 2017-03-12 03:29:04 -04:00
Jun Wu
ce549d6536 lock: include Linux pid namespace identifier in prefix
Previously, the lock only contains a hostname as an attempt to detect pid
namespace difference. However, that's not enough on modern Linux - a single
hostname could have different pid namespaces.

That means if people run hg inside different PID namespaces with a same UTS
namespae, the lock would be broken - an hg proccess in pid namespace A will
think the lock having a "random" pid in pid namespace B is "dead" and remove
it.

This patch solves the above issue by appending an PID namespace identifier of
the current process to the lock prefix ("hostname"). It depends on /proc
being mounted properly. But I don't think there is a better way to get pid
namespace identifier reliably.
2017-02-10 13:56:31 -08:00
Jun Wu
a0109d181e lock: move lock._host calculation to a function
This allows customization per platform. See the next patch for why.
2017-02-10 13:35:21 -08:00
Gregory Szorc
5120867e9f lock: clear postrelease hooks list after usage
Post release hooks should only be called once. Setting the
list to None after usage will prevent accidental usage after
they are used.

In addition, it is easy for reference cycles to sneak into hook
functions. Clearing the hooks after usage helps prevent these
cycles.
2016-04-16 09:00:15 -07:00
timeless
3502e556ef util: enable getpid to be replaced
This will enable tests to write stable process ids.
2016-02-03 09:11:22 +00:00
Bryan O'Sullivan
2e67496298 lock: turn a lock into a Python context manager
This lets us greatly simply acquire/release cycles.

Code pattern before:

  try:
    lock = repo.lock()
    # zillions of lines of code
  finally:
    lock.release()

And after:

  with repo.lock():
    # ...
2016-01-15 13:14:45 -08:00
Siddharth Agarwal
eb9c8405ac lock: add a way to prevent locks from being inherited
We want to prevent locks from being inherited sometimes (e.g. when there's a
currently running transaction, which will break a lot of assumptions we're
making in here.)
2015-10-06 13:13:31 -07:00
Siddharth Agarwal
fb3839770e lock.release: don't call postrelease functions for inherited locks
Review feedback from Pierre-Yves David. The postrelease functions typically
assume the lock is not held at all.
2015-10-04 20:04:44 -07:00
Siddharth Agarwal
536de184ae lock: turn prepinherit/reacquire into a single context manager
Review feedback from Pierre-Yves David. This makes the overall code cleaner and
less error-prone, and makes a previously explicitly checked error state
impossible.
2015-10-04 20:02:50 -07:00
Siddharth Agarwal
4a04cef0a1 lock: recognize parent locks while acquiring
This is part of a series that will allow locks to be inherited by subprocesses
in limited circumstances. This patch enables the logic introduced in previous
patches.
2015-09-24 22:07:55 -07:00
Siddharth Agarwal
066d0055bc lock: add a wrapper to os.getpid() to make testing easier
This will allow us to fake locks across processes more easily.
2015-09-24 21:26:37 -07:00
Siddharth Agarwal
ce3fd41292 lock.release: do not unlink inherited locks
This is part of a series that will allow locks to be inherited by subprocesses
in limited circumstances. A subprocess unlinking a lock will lead to potential
corruption from other concurrent processes.
2015-09-24 16:03:26 -07:00
Siddharth Agarwal
9fe251823c lock: add a method to reacquire the lock after subprocesses exit
This is part of a series that will allow locks to be inherited by subprocesses
in limited circumstances.
2015-09-24 16:00:41 -07:00
Siddharth Agarwal
781395377d lock: add a method to prepare the lock for inheritance
This is part of a series that will allow locks to be inherited by subprocesses
in limited circumstances.
2015-09-24 10:37:13 -07:00
Siddharth Agarwal
3efac149fd lock: introduce state to keep track of inheritance
This is part of a series that will allow locks to be inherited by subprocesses
in limited circumstances. In upcoming patches we will refer to this state.
2015-09-24 15:57:11 -07:00
Siddharth Agarwal
0edaba580a lock: move acquirefn call to inside the lock
We're going to need to call it again as part of reinitialization after a
subprocess inherits the lock.
2015-09-22 14:09:42 -07:00
Siddharth Agarwal
156c95bc3e lock: factor out lock testing into a separate function
This is going to be needed for upcoming work with lock inheritance.
2015-09-16 19:52:06 -07:00
Siddharth Agarwal
bf15e8d025 lock: factor code to read lock into a separate function
This is going to be needed for upcoming work with lock inheritance.
2015-09-16 19:26:59 -07:00
Matt Mackall
2508b23060 lock: make trylock private 2015-08-24 13:26:10 -05:00
Matt Mackall
228882fcf1 lock: loop a finite number of times in trylock (issue4787)
..before falling back to lock, which will sleep. This only addresses
the CPU consumption of the reported issue.
2015-08-24 13:24:43 -05:00
Gregory Szorc
c3a5d84ca1 lock: use absolute_import 2015-08-08 19:30:17 -07:00
Gregory Szorc
5380dea2a7 global: mass rewrite to use modern exception syntax
Python 2.6 introduced the "except type as instance" syntax, replacing
the "except type, instance" syntax that came before. Python 3 dropped
support for the latter syntax. Since we no longer support Python 2.4 or
2.5, we have no need to continue supporting the "except type, instance".

This patch mass rewrites the exception syntax to be Python 2.6+ and
Python 3 compatible.

This patch was produced by running `2to3 -f except -w -n .`.
2015-06-23 22:20:08 -07:00
Siddharth Agarwal
146e346b87 lock: while releasing, unlink lockfile even if the release function throws
Consider a hypothetical bug in the release function that causes it to raise an
exception. Also consider the bisect command, which saves its state in a finally
clause. Saving the state requires acquiring the wlock.

If we don't unlink the lockfile when the exception is thrown, we'll try to
acquire the wlock again. We're going to try and acquire a lock again while our
old lockfile is on disk. The PID on disk is our own, and of course we're still
running, so we won't take over the lock. Hence we'll be stuck waiting for a
lock that we left behind ourselves.

To avoid this, always unlink the lockfile. This preserves the invariant that
self.held > 0 is equivalent to the lockfile existing on disk.
2014-10-16 19:15:51 -07:00
Mads Kiilerich
2e26bbb4c8 localrepo: give a sigh of relief when getting lock after waiting for it
A message like this was sometimes shown when pushing:
  remote: waiting for lock on repository foo held by 'mercurial:20858'
That could scare users, making them wonder whether the push actually succeeded.

To mitigate that fear, issue an additional "warning" such as:
  got lock after 2 seconds

The return value from lock.lock.lock() was unused - instead we return the
delay.

This also adds the first test coverage for waiting for locks.
2014-02-06 01:55:09 +01:00
FUJIWARA Katsunori
cf37230008 lock: take both vfs and lock file path relative to vfs to access via vfs
This patch makes "lock.lock.__init__()" take both vfs and lock file
path relative to vfs, instead of absolute path to lock file.

This allows lock file to be accessed via vfs.
2013-11-12 16:23:52 +09:00
Yuya Nishihara
a87a5e29b1 lock: handle race in trylock/testlock on Windows
readlock may raise IOError if the system does not support symlink.
2013-10-02 21:16:40 +09:00
Bryan O'Sullivan
7d3941d67f lock: if we fork, ensure that only the parent releases
This prevents us from having a bunch of errant worker processes all try
to release a lock if a problem occurs. (Releasing the lock more than once
is harmless; it's invoking the associated callbacks we want to avoid.)
2013-04-11 13:30:27 -07:00
Matt Mackall
721e01ea74 merge with stable 2012-09-29 12:28:52 -05:00
Tomasz Kleczek
7063833db6 lock: fixed race condition in trylock/testlock (issue3506)
Suppose the following scenario:

1. Process A takes the lock (e.g. on commit).
2. Process B wants to grab the lock. Since lock file exists
   the exception is raised. In the catch block the testlock
   function is called.
3. Process A releases the lock.
4. Process B tries to read the lock file as a part of testlock
   function. This results in OSError (ENOENT) and since we're
   not inside the exception handler function this is propagated
   and aborts the whole operation.

To fix this we now check in testlock function whether lock file
actually exists and if not (i.e. if readlock fails) we just return.
2012-09-27 14:38:03 -07:00
Bryan O'Sullivan
dc9ede17dc Merge spelling fixes 2012-09-11 08:36:09 -07:00
timeless@mozdev.org
9a22975e4d spelling: release 2012-08-17 13:58:18 -07:00
Mads Kiilerich
e973af65d0 improve some comments and docstrings, fixing issues found when spell checking 2012-08-21 02:41:20 +02:00
Mads Kiilerich
2f4504e446 fix trivial spelling errors 2012-08-15 22:38:42 +02:00
Matt Mackall
2e8aaf75f9 lock: change name of release chain 2011-11-30 16:53:44 -06:00
Pierre-Yves David
a72322069e lock: add mechanism to register post release callback 2011-11-28 15:05:26 +01:00
Martin Geisler
af8a35e078 check-code: flag 0/1 used as constant Boolean expression 2011-06-01 12:38:46 +02:00
Adrian Buehlmann
7f4eeda8e6 lock: use util.unlink (issue2537) 2011-01-11 14:10:16 +01:00
Matt Mackall
595d66f424 Update license to GPLv2+ 2010-01-19 22:20:08 -06:00
Benoit Boissinot
8b1492e457 lock: the correct way to do a trylock() is to use a timeout of 0 2009-11-16 11:55:29 +01:00
Benoit Boissinot
16abbe4cd8 lock: catch specific exceptions 2009-10-31 18:10:52 +01:00
Benoit Boissinot
d2dcc4c950 lock: use '==' instead of 'is' for integer equality ('is' may not work) 2009-10-31 17:07:12 +01:00
Greg Ward
80075c97bf localrepo: document the locking scheme a little better
- localrepo: document lock(), wlock() methods
- lock: add class docstring
2009-08-05 14:42:57 +02:00
Simon Heimberg
09ac1e6c92 separate import lines from mercurial and general python modules 2009-04-28 17:40:46 +02:00
Martin Geisler
750183bdad updated license to be explicit about GPL version 2 2009-04-26 01:08:54 +02:00
Ronny Pfannschmidt
23e91269e5 add a deprecation warning for gc based lock releasing 2009-04-22 02:01:22 +02:00
Ronny Pfannschmidt
f55e3eb9a7 made repo locks recursive and deprecate refcounting based lock releasing
all locks should use the explicit lock.release

mercurial.lock.lock.__del__ handles unwrapping recursive locks

localrepo.lock/wlock are still using weakref in order to keep backward
compatibiltiy to releasing locks via garbage collection
by ensuring the release on __del__
2009-04-22 02:01:22 +02:00