diff options
| author | Joshua Harlow <harlowja@gmail.com> | 2014-08-12 19:11:30 -0700 |
|---|---|---|
| committer | Joshua Harlow <harlowja@yahoo-inc.com> | 2014-09-16 11:27:39 -0700 |
| commit | 37a80126f2be04f11dd3d56465de103bd8578782 (patch) | |
| tree | e3495477876b2591d35ee30f3e6d6a94dc5fc1e4 /tooz/drivers/ipc.py | |
| parent | c5e1c3f96f016c9ddfff8206d1bebeaf4ea44e6c (diff) | |
| download | tooz-37a80126f2be04f11dd3d56465de103bd8578782.tar.gz | |
Use the more reliable sysv_ipc instead of posix_ipc+lockutils
Remove the usage of lockutils (and surronding oslo modules)
and keep it much simpler by just using the sysv_ipc module
directly.
This adjustment reduces the complexity, test exposure and
API complexity of tooz; removing much of the complex functionality
that was pulled in when sucking in the lockutils module for its
simple (but still broken) posix_ipc logic.
Change-Id: I46db9bda252473317a0f3d65fe0329ac2151f332
Diffstat (limited to 'tooz/drivers/ipc.py')
| -rw-r--r-- | tooz/drivers/ipc.py | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/tooz/drivers/ipc.py b/tooz/drivers/ipc.py index 0e2a013..1f1c4f7 100644 --- a/tooz/drivers/ipc.py +++ b/tooz/drivers/ipc.py @@ -15,32 +15,93 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -import posix_ipc + +import hashlib + +import six +import sysv_ipc import tooz from tooz import coordination from tooz import locking -from tooz.openstack.common import lockutils + +if sysv_ipc.KEY_MIN <= 0: + _KEY_RANGE = abs(sysv_ipc.KEY_MIN) + sysv_ipc.KEY_MAX +else: + _KEY_RANGE = sysv_ipc.KEY_MAX - sysv_ipc.KEY_MIN class IPCLock(locking.Lock): - _LOCK_PREFIX = b'_tooz_' + """A sysv IPC based lock. + + Please ensure you have read over (and understand) the limitations of sysv + IPC locks, and especially have tried and used $ ipcs -l (note the maximum + number of semaphores system wide field that command outputs). To ensure + that you do not reach that limit it is recommended to use destroy() at + the correct program exit/entry points. + """ + _LOCK_PROJECT = b'__TOOZ_LOCK_' def __init__(self, name, timeout): - self.lock = lockutils.external_lock( - (self._LOCK_PREFIX + name).decode('ascii')) + super(IPCLock, self).__init__(name) + self.key = self.ftok(name, self._LOCK_PROJECT) + try: + self.lock = sysv_ipc.Semaphore(self.key, + flags=sysv_ipc.IPC_CREX, + initial_value=1) + except sysv_ipc.ExistentialError: + self.lock = sysv_ipc.Semaphore(self.key) + self.lock.undo = True self.timeout = timeout + @staticmethod + def ftok(name, project): + # Similar to ftok & http://semanchuk.com/philip/sysv_ipc/#ftok_weakness + # but hopefully without as many weaknesses... + h = hashlib.md5() + if not isinstance(project, six.binary_type): + project = project.encode('ascii') + h.update(project) + if not isinstance(name, six.binary_type): + name = name.encode('ascii') + h.update(name) + return (int(h.hexdigest(), 16) % _KEY_RANGE) + sysv_ipc.KEY_MIN + def acquire(self, blocking=True): timeout = self.timeout if blocking else 0 try: - return bool(self.lock.acquire(timeout=timeout)) - # TODO(jd) This should be encapsulated in lockutils! - except posix_ipc.BusyError: + self.lock.acquire(timeout=timeout) + except (sysv_ipc.BusyError, sysv_ipc.ExistentialError): return False + else: + return True def release(self): - return self.lock.release() + try: + self.lock.release() + except sysv_ipc.ExistentialError: + return False + else: + return True + + def destroy(self): + """This will destroy the lock. + + NOTE(harlowja): this will destroy the lock, and if it is being shared + across processes this can have unintended consquences, so it *must* + only be used when it is *safe* to remove it (ie at a known program + exit point, where it can be ensured that no other process will be + using it, or that if other processes are using it they can tolerate + it being destroyed). + + Read your man pages for `semctl(IPC_RMID)` before using this to + understand its side-effects on other programs that *may* be + concurrently using the same lock while it is being destroyed... + """ + try: + self.lock.remove() + except sysv_ipc.ExistentialError: + pass class IPCDriver(coordination.CoordinationDriver): |
