"""
from ctypes import CDLL, c_char_p, c_size_t, c_void_p, c_char, c_int, c_long, \
c_ulong, create_string_buffer, byref, Structure, c_uint64, c_ubyte, \
- pointer, CFUNCTYPE, c_int64
+ pointer, CFUNCTYPE, c_int64, c_uint8
from ctypes.util import find_library
import ctypes
import errno
""" `ObjectExists` class, derived from `Error` """
pass
+class ObjectBusy(Error):
+ """ `ObjectBusy` class, derived from `Error` """
+ pass
+
class IOError(Error):
""" `IOError` class, derived from `Error` """
pass
errno.EIO : IOError,
errno.ENOSPC : NoSpace,
errno.EEXIST : ObjectExists,
+ errno.EBUSY : ObjectBusy,
errno.ENODATA : NoData,
errno.EINTR : InterruptedOrTimeoutError,
errno.ETIMEDOUT : TimedOut
("kb_avail", c_uint64),
("num_objects", c_uint64)]
+class timeval(Structure):
+ _fields_ = [("tv_sec", c_long), ("tv_usec", c_long)]
+
+
class Version(object):
""" Version information """
def __init__(self, major, minor, extra):
self.require_ioctx_open()
return run_in_thread(self.librados.rados_get_last_version, (self.io,))
+ def lock_exclusive(self, key, name, cookie, desc="", duration=None, flags=0):
+
+ """
+ Take an exclusive lock on an object
+
+ :param key: name of the object
+ :type key: str
+ :param name: name of the lock
+ :type name: str
+ :param cookie: cookie of the lock
+ :type cookie: str
+ :param desc: description of the lock
+ :type desc: str
+ :param duration: duration of the lock in seconds
+ :type duration: int
+ :param flags: flags
+ :type flags: int
+
+ :raises: :class:`TypeError`
+ :raises: :class:`Error`
+ """
+ self.require_ioctx_open()
+ if not isinstance(key, str):
+ raise TypeError('key must be a string')
+ if not isinstance(name, str):
+ raise TypeError('name must be a string')
+ if not isinstance(cookie, str):
+ raise TypeError('cookie must be a string')
+ if not isinstance(desc, str):
+ raise TypeError('desc must be a string')
+ if duration is not None and not isinstance(duration, int):
+ raise TypeError('duration must be a integer')
+ if not isinstance(flags, int):
+ raise TypeError('flags must be a integer')
+
+ ret = run_in_thread(self.librados.rados_lock_exclusive,
+ (self.io, c_char_p(key), c_char_p(name), c_char_p(cookie),
+ c_char_p(desc),
+ timeval(duration, None) if duration is None else None,
+ c_uint8(flags)))
+ if ret < 0:
+ raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
+
+ def lock_shared(self, key, name, cookie, tag, desc="", duration=None, flags=0):
+
+ """
+ Take a shared lock on an object
+
+ :param key: name of the object
+ :type key: str
+ :param name: name of the lock
+ :type name: str
+ :param cookie: cookie of the lock
+ :type cookie: str
+ :param tag: tag of the lock
+ :type tag: str
+ :param desc: description of the lock
+ :type desc: str
+ :param duration: duration of the lock in seconds
+ :type duration: int
+ :param flags: flags
+ :type flags: int
+
+ :raises: :class:`TypeError`
+ :raises: :class:`Error`
+ """
+ self.require_ioctx_open()
+ if not isinstance(key, str):
+ raise TypeError('key must be a string')
+ if not isinstance(name, str):
+ raise TypeError('name must be a string')
+ if not isinstance(cookie, str):
+ raise TypeError('cookie must be a string')
+ if not isinstance(tag, str):
+ raise TypeError('tag must be a string')
+ if not isinstance(desc, str):
+ raise TypeError('desc must be a string')
+ if duration is not None and not isinstance(duration, int):
+ raise TypeError('duration must be a integer')
+ if not isinstance(flags, int):
+ raise TypeError('flags must be a integer')
+
+ ret = run_in_thread(self.librados.rados_lock_shared,
+ (self.io, c_char_p(key), c_char_p(name), c_char_p(cookie),
+ c_char_p(tag), c_char_p(desc),
+ timeval(duration, None) if duration is None else None,
+ c_uint8(flags)))
+ if ret < 0:
+ raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
+
+ def unlock(self, key, name, cookie):
+
+ """
+ Release a shared or exclusive lock on an object
+
+ :param key: name of the object
+ :type key: str
+ :param name: name of the lock
+ :type name: str
+ :param cookie: cookie of the lock
+ :type cookie: str
+
+ :raises: :class:`TypeError`
+ :raises: :class:`Error`
+ """
+ self.require_ioctx_open()
+ if not isinstance(key, str):
+ raise TypeError('key must be a string')
+ if not isinstance(name, str):
+ raise TypeError('name must be a string')
+ if not isinstance(cookie, str):
+ raise TypeError('cookie must be a string')
+
+ ret = run_in_thread(self.librados.rados_unlock,
+ (self.io, c_char_p(key), c_char_p(name), c_char_p(cookie)))
+ if ret < 0:
+ raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
+
+
+
def set_object_locator(func):
def retfunc(self, *args, **kwargs):
if self.locator_key is not None:
from nose.tools import eq_ as eq, assert_raises
from rados import (Rados, Error, Object, ObjectExists, ObjectNotFound,
+ ObjectBusy,
ANONYMOUS_AUID, ADMIN_AUID, LIBRADOS_ALL_NSPACES)
import time
import threading
[i.remove() for i in self.ioctx.list_objects()]
+ def test_lock(self):
+ self.ioctx.lock_exclusive("foo", "lock", "locker", "desc_lock",
+ 10000, 0)
+ assert_raises(ObjectExists,
+ self.ioctx.lock_exclusive,
+ "foo", "lock", "locker", "desc_lock", 10000, 0)
+ self.ioctx.unlock("foo", "lock", "locker")
+ assert_raises(ObjectNotFound, self.ioctx.unlock, "foo", "lock", "locker")
+
+ self.ioctx.lock_shared("foo", "lock", "locker1", "tag", "desc_lock",
+ 10000, 0)
+ self.ioctx.lock_shared("foo", "lock", "locker2", "tag", "desc_lock",
+ 10000, 0)
+ assert_raises(ObjectBusy,
+ self.ioctx.lock_exclusive,
+ "foo", "lock", "locker3", "desc_lock", 10000, 0)
+ self.ioctx.unlock("foo", "lock", "locker1")
+ self.ioctx.unlock("foo", "lock", "locker2")
+ assert_raises(ObjectNotFound, self.ioctx.unlock, "foo", "lock", "locker1")
+ assert_raises(ObjectNotFound, self.ioctx.unlock, "foo", "lock", "locker2")
+
+
class TestObject(object):
def setUp(self):