Files
deb-python-taskflow/taskflow/utils/lock_utils.py
Joshua Harlow 166bfff48c Add a directory/filesystem based persistence layer
Add a nice non-memory-based but also non-db based
persistence layer which is another good example of
how a persistence layer can be created (and used).

Example directory structure:

  /books
  /books/247c5311-d4ec-461b-9e76-51830d6a75b2
  /books/247c5311-d4ec-461b-9e76-51830d6a75b2/metadata
  /books/247c5311-d4ec-461b-9e76-51830d6a75b2/flows
  /books/247c5311-d4ec-461b-9e76-51830d6a75b2/flows/25f18828-a067-411e-9035-8217536f925d
  /flows
  /flows/25f18828-a067-411e-9035-8217536f925d
  /flows/25f18828-a067-411e-9035-8217536f925d/metadata
  /flows/25f18828-a067-411e-9035-8217536f925d/tasks
  /flows/25f18828-a067-411e-9035-8217536f925d/tasks/a352fa2e-82cf-4c37-89ae-3aa10dbf1437
  /tasks
  /tasks/a352fa2e-82cf-4c37-89ae-3aa10dbf1437

Change-Id: I63aaf56497187e21469bc500a49dd02de0c67f29
2013-09-21 23:55:33 -07:00

111 lines
3.6 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# This is a modified version of what was in oslo-incubator lockutils.py from
# commit 5039a610355e5265fb9fbd1f4023e8160750f32e but this one does not depend
# on oslo.cfg or the very large oslo-incubator oslo logging module (which also
# pulls in oslo.cfg) and is reduced to only what taskflow currently wants to
# use from that code.
import errno
import logging
import os
import time
LOG = logging.getLogger(__name__)
WAIT_TIME = 0.01
class _InterProcessLock(object):
"""Lock implementation which allows multiple locks, working around
issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does
not require any cleanup. Since the lock is always held on a file
descriptor rather than outside of the process, the lock gets dropped
automatically if the process crashes, even if __exit__ is not executed.
There are no guarantees regarding usage by multiple green threads in a
single process here. This lock works only between processes.
Note these locks are released when the descriptor is closed, so it's not
safe to close the file descriptor while another green thread holds the
lock. Just opening and closing the lock file can break synchronisation,
so lock files must be accessed only using this abstraction.
"""
def __init__(self, name):
self._lockfile = None
self._fname = name
@property
def path(self):
return self._fname
def __enter__(self):
self._lockfile = open(self.path, 'w')
while True:
try:
# Using non-blocking locks since green threads are not
# patched to deal with blocking locking calls.
# Also upon reading the MSDN docs for locking(), it seems
# to have a laughable 10 attempts "blocking" mechanism.
self.trylock()
return self
except IOError as e:
if e.errno in (errno.EACCES, errno.EAGAIN):
time.sleep(WAIT_TIME)
else:
raise
def __exit__(self, exc_type, exc_val, exc_tb):
try:
self.unlock()
self._lockfile.close()
except IOError:
LOG.exception("Could not release the acquired lock `%s`",
self.path)
def trylock(self):
raise NotImplementedError()
def unlock(self):
raise NotImplementedError()
class _WindowsLock(_InterProcessLock):
def trylock(self):
msvcrt.locking(self._lockfile.fileno(), msvcrt.LK_NBLCK, 1)
def unlock(self):
msvcrt.locking(self._lockfile.fileno(), msvcrt.LK_UNLCK, 1)
class _PosixLock(_InterProcessLock):
def trylock(self):
fcntl.lockf(self._lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
def unlock(self):
fcntl.lockf(self._lockfile, fcntl.LOCK_UN)
if os.name == 'nt':
import msvcrt
InterProcessLock = _WindowsLock
else:
import fcntl
InterProcessLock = _PosixLock