Commit bb38965c authored by Klaus Aehlig's avatar Klaus Aehlig
Browse files

Handle lock addition as lock acquisitions



From stable-2.12 onwards no longer are explicitly added; they just
exist for all conceivable names/uuids. Nevertheless, addition was
handled special based on the assumption that no one else can have
a lock on an entity that is just being created.

This assumption, however, is wrong for instance names. Consider
the situation that an instance is first destroyed an then an instance
with the same name is created. While is instance is being destroyed,
there is the situation where the instance is still in the configuration
and the destroy job holds a lock on the instance. In that time, another
job, like group_verify_disks, can read the list of instances, decide
to wait for a lock on all the then existing instances, and eventually
get the locks, including the one on the instance just removed. And
while that job still has the (useless) lock, the new creation job can
come to the lock-addition stage.

To live with the presence of those races, just wait for newly added
locks as for any other locks. Any job with a lock on a no longer existing
entity will release it pretty soon anyway.
Signed-off-by: default avatarKlaus Aehlig <aehlig@google.com>
Reviewed-by: default avatarPetr Pudlak <pudlak@google.com>
parent 45827af8
......@@ -506,41 +506,16 @@ class Processor(object):
if acquiring_locks:
# Acquiring locks
needed_locks = lu.needed_locks[level]
self._AcquireLocks(level, needed_locks, share, opportunistic,
calc_timeout())
lu.wconfdlocks = self.wconfd.Client().ListLocks(self._wconfdcontext)
use_opportunistic = opportunistic
else:
# Adding locks
add_locks = _LockList(lu.add_locks[level])
lu.remove_locks[level] = add_locks
try:
levelname = locking.LEVEL_NAMES[level]
if share:
mode = "shared"
else:
mode = "exclusive"
needed_locks = _LockList(lu.add_locks[level])
lu.remove_locks[level] = needed_locks
use_opportunistic = False
request = [["%s/%s" % (levelname, lock), mode]
for lock in add_locks]
logging.debug("Requesting %s for %s",
request, self._wconfdcontext)
blocked = self.wconfd.Client().TryUpdateLocks(self._wconfdcontext,
request)
assert blocked == [], "Allocating newly 'created' locks failed"
lu.wconfdlocks = \
self.wconfd.Client().ListLocks(self._wconfdcontext)
except errors.GenericError:
# TODO: verify what actually caused the error
logging.exception("Detected lock error in level %s for locks"
" %s, shared=%s", level, add_locks, share)
raise errors.OpPrereqError(
"Couldn't add locks (%s), most likely because of another"
" job who added them first" % add_locks,
errors.ECODE_NOTUNIQUE)
self._AcquireLocks(level, needed_locks, share, use_opportunistic,
calc_timeout())
lu.wconfdlocks = self.wconfd.Client().ListLocks(self._wconfdcontext)
try:
result = self._LockAndExecLU(lu, level + 1, calc_timeout)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment