1 # cython: embedsignature=True
3 This module is a thin wrapper around librados.
5 Error codes from librados are turned into exceptions that subclass
6 :class:`Error`. Almost all methods may raise :class:`Error(the base class of all rados exceptions), :class:`PermissionError`
7 (the base class of all rados exceptions), :class:`PermissionError`
8 and :class:`IOError`, in addition to those documented for the
11 # Copyright 2011 Josh Durgin
12 # Copyright 2011, Hannu Valtonen <hannu.valtonen@ormod.com>
13 # Copyright 2015 Hector Martin <marcan@marcan.st>
14 # Copyright 2016 Mehdi Abaakouk <sileht@redhat.com>
16 from cpython cimport PyObject, ref
17 from cpython.pycapsule cimport *
18 from libc cimport errno
19 from libc.stdint cimport *
20 from libc.stdlib cimport malloc, realloc, free
26 from collections import Callable
27 from datetime import datetime
28 from functools import partial, wraps
29 from itertools import chain
31 # Are we running Python 2.x
32 if sys.version_info[0] < 3:
38 cdef extern from "Python.h":
39 # These are in cpython/string.pxd, but use "object" types instead of
40 # PyObject*, which invokes assumptions in cpython that we need to
41 # legitimately break to implement zero-copy string buffers in Ioctx.read().
42 # This is valid use of the Python API and documented as a special case.
43 PyObject *PyBytes_FromStringAndSize(char *v, Py_ssize_t len) except NULL
44 char* PyBytes_AsString(PyObject *string) except NULL
45 int _PyBytes_Resize(PyObject **string, Py_ssize_t newsize) except -1
46 void PyEval_InitThreads()
49 cdef extern from "time.h":
50 ctypedef long int time_t
51 ctypedef long int suseconds_t
54 cdef extern from "sys/time.h":
60 cdef extern from "rados/rados_types.h" nogil:
61 cdef char* _LIBRADOS_ALL_NSPACES "LIBRADOS_ALL_NSPACES"
64 cdef extern from "rados/librados.h" nogil:
66 _LIBRADOS_OP_FLAG_EXCL "LIBRADOS_OP_FLAG_EXCL"
67 _LIBRADOS_OP_FLAG_FAILOK "LIBRADOS_OP_FLAG_FAILOK"
68 _LIBRADOS_OP_FLAG_FADVISE_RANDOM "LIBRADOS_OP_FLAG_FADVISE_RANDOM"
69 _LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL "LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL"
70 _LIBRADOS_OP_FLAG_FADVISE_WILLNEED "LIBRADOS_OP_FLAG_FADVISE_WILLNEED"
71 _LIBRADOS_OP_FLAG_FADVISE_DONTNEED "LIBRADOS_OP_FLAG_FADVISE_DONTNEED"
72 _LIBRADOS_OP_FLAG_FADVISE_NOCACHE "LIBRADOS_OP_FLAG_FADVISE_NOCACHE"
76 _LIBRADOS_OPERATION_NOFLAG "LIBRADOS_OPERATION_NOFLAG"
77 _LIBRADOS_OPERATION_BALANCE_READS "LIBRADOS_OPERATION_BALANCE_READS"
78 _LIBRADOS_OPERATION_LOCALIZE_READS "LIBRADOS_OPERATION_LOCALIZE_READS"
79 _LIBRADOS_OPERATION_ORDER_READS_WRITES "LIBRADOS_OPERATION_ORDER_READS_WRITES"
80 _LIBRADOS_OPERATION_IGNORE_CACHE "LIBRADOS_OPERATION_IGNORE_CACHE"
81 _LIBRADOS_OPERATION_SKIPRWLOCKS "LIBRADOS_OPERATION_SKIPRWLOCKS"
82 _LIBRADOS_OPERATION_IGNORE_OVERLAY "LIBRADOS_OPERATION_IGNORE_OVERLAY"
83 _LIBRADOS_CREATE_EXCLUSIVE "LIBRADOS_CREATE_EXCLUSIVE"
84 _LIBRADOS_CREATE_IDEMPOTENT "LIBRADOS_CREATE_IDEMPOTENT"
86 cdef uint64_t _LIBRADOS_SNAP_HEAD "LIBRADOS_SNAP_HEAD"
88 ctypedef void* rados_t
89 ctypedef void* rados_config_t
90 ctypedef void* rados_ioctx_t
91 ctypedef void* rados_xattrs_iter_t
92 ctypedef void* rados_omap_iter_t
93 ctypedef void* rados_list_ctx_t
94 ctypedef uint64_t rados_snap_t
95 ctypedef void *rados_write_op_t
96 ctypedef void *rados_read_op_t
97 ctypedef void *rados_completion_t
98 ctypedef void (*rados_callback_t)(rados_completion_t cb, void *arg)
99 ctypedef void (*rados_log_callback_t)(void *arg, const char *line, const char *who,
100 uint64_t sec, uint64_t nsec, uint64_t seq, const char *level, const char *msg)
101 ctypedef void (*rados_log_callback2_t)(void *arg, const char *line, const char *who, const char *name,
102 uint64_t sec, uint64_t nsec, uint64_t seq, const char *level, const char *msg)
105 cdef struct rados_cluster_stat_t:
111 cdef struct rados_pool_stat_t:
115 uint64_t num_object_clones
116 uint64_t num_object_copies
117 uint64_t num_objects_missing_on_primary
118 uint64_t num_objects_unfound
119 uint64_t num_objects_degraded
125 void rados_buffer_free(char *buf)
127 void rados_version(int *major, int *minor, int *extra)
128 int rados_create2(rados_t *pcluster, const char *const clustername,
129 const char * const name, uint64_t flags)
130 int rados_create_with_context(rados_t *cluster, rados_config_t cct)
131 int rados_connect(rados_t cluster)
132 void rados_shutdown(rados_t cluster)
133 int rados_conf_read_file(rados_t cluster, const char *path)
134 int rados_conf_parse_argv_remainder(rados_t cluster, int argc, const char **argv, const char **remargv)
135 int rados_conf_parse_env(rados_t cluster, const char *var)
136 int rados_conf_set(rados_t cluster, char *option, const char *value)
137 int rados_conf_get(rados_t cluster, char *option, char *buf, size_t len)
139 int rados_ioctx_pool_stat(rados_ioctx_t io, rados_pool_stat_t *stats)
140 int64_t rados_pool_lookup(rados_t cluster, const char *pool_name)
141 int rados_pool_reverse_lookup(rados_t cluster, int64_t id, char *buf, size_t maxlen)
142 int rados_pool_create(rados_t cluster, const char *pool_name)
143 int rados_pool_create_with_auid(rados_t cluster, const char *pool_name, uint64_t auid)
144 int rados_pool_create_with_crush_rule(rados_t cluster, const char *pool_name, uint8_t crush_rule_num)
145 int rados_pool_create_with_all(rados_t cluster, const char *pool_name, uint64_t auid, uint8_t crush_rule_num)
146 int rados_pool_get_base_tier(rados_t cluster, int64_t pool, int64_t *base_tier)
147 int rados_pool_list(rados_t cluster, char *buf, size_t len)
148 int rados_pool_delete(rados_t cluster, const char *pool_name)
149 int rados_inconsistent_pg_list(rados_t cluster, int64_t pool, char *buf, size_t len)
151 int rados_cluster_stat(rados_t cluster, rados_cluster_stat_t *result)
152 int rados_cluster_fsid(rados_t cluster, char *buf, size_t len)
153 int rados_blacklist_add(rados_t cluster, char *client_address, uint32_t expire_seconds)
155 int rados_ping_monitor(rados_t cluster, const char *mon_id, char **outstr, size_t *outstrlen)
156 int rados_mon_command(rados_t cluster, const char **cmd, size_t cmdlen,
157 const char *inbuf, size_t inbuflen,
158 char **outbuf, size_t *outbuflen,
159 char **outs, size_t *outslen)
160 int rados_mgr_command(rados_t cluster, const char **cmd, size_t cmdlen,
161 const char *inbuf, size_t inbuflen,
162 char **outbuf, size_t *outbuflen,
163 char **outs, size_t *outslen)
164 int rados_mon_command_target(rados_t cluster, const char *name, const char **cmd, size_t cmdlen,
165 const char *inbuf, size_t inbuflen,
166 char **outbuf, size_t *outbuflen,
167 char **outs, size_t *outslen)
168 int rados_osd_command(rados_t cluster, int osdid, const char **cmd, size_t cmdlen,
169 const char *inbuf, size_t inbuflen,
170 char **outbuf, size_t *outbuflen,
171 char **outs, size_t *outslen)
172 int rados_pg_command(rados_t cluster, const char *pgstr, const char **cmd, size_t cmdlen,
173 const char *inbuf, size_t inbuflen,
174 char **outbuf, size_t *outbuflen,
175 char **outs, size_t *outslen)
176 int rados_monitor_log(rados_t cluster, const char *level, rados_log_callback_t cb, void *arg)
177 int rados_monitor_log2(rados_t cluster, const char *level, rados_log_callback2_t cb, void *arg)
179 int rados_wait_for_latest_osdmap(rados_t cluster)
181 int rados_ioctx_create(rados_t cluster, const char *pool_name, rados_ioctx_t *ioctx)
182 void rados_ioctx_destroy(rados_ioctx_t io)
183 int rados_ioctx_pool_set_auid(rados_ioctx_t io, uint64_t auid)
184 void rados_ioctx_locator_set_key(rados_ioctx_t io, const char *key)
185 void rados_ioctx_set_namespace(rados_ioctx_t io, const char * nspace)
187 uint64_t rados_get_last_version(rados_ioctx_t io)
188 int rados_stat(rados_ioctx_t io, const char *o, uint64_t *psize, time_t *pmtime)
189 int rados_write(rados_ioctx_t io, const char *oid, const char *buf, size_t len, uint64_t off)
190 int rados_write_full(rados_ioctx_t io, const char *oid, const char *buf, size_t len)
191 int rados_append(rados_ioctx_t io, const char *oid, const char *buf, size_t len)
192 int rados_read(rados_ioctx_t io, const char *oid, char *buf, size_t len, uint64_t off)
193 int rados_remove(rados_ioctx_t io, const char *oid)
194 int rados_trunc(rados_ioctx_t io, const char *oid, uint64_t size)
195 int rados_getxattr(rados_ioctx_t io, const char *o, const char *name, char *buf, size_t len)
196 int rados_setxattr(rados_ioctx_t io, const char *o, const char *name, const char *buf, size_t len)
197 int rados_rmxattr(rados_ioctx_t io, const char *o, const char *name)
198 int rados_getxattrs(rados_ioctx_t io, const char *oid, rados_xattrs_iter_t *iter)
199 int rados_getxattrs_next(rados_xattrs_iter_t iter, const char **name, const char **val, size_t *len)
200 void rados_getxattrs_end(rados_xattrs_iter_t iter)
202 int rados_nobjects_list_open(rados_ioctx_t io, rados_list_ctx_t *ctx)
203 int rados_nobjects_list_next(rados_list_ctx_t ctx, const char **entry, const char **key, const char **nspace)
204 void rados_nobjects_list_close(rados_list_ctx_t ctx)
206 int rados_ioctx_snap_rollback(rados_ioctx_t io, const char * oid, const char * snapname)
207 int rados_ioctx_snap_create(rados_ioctx_t io, const char * snapname)
208 int rados_ioctx_snap_remove(rados_ioctx_t io, const char * snapname)
209 int rados_ioctx_snap_lookup(rados_ioctx_t io, const char * name, rados_snap_t * id)
210 int rados_ioctx_snap_get_name(rados_ioctx_t io, rados_snap_t id, char * name, int maxlen)
211 void rados_ioctx_snap_set_read(rados_ioctx_t io, rados_snap_t snap)
212 int rados_ioctx_snap_list(rados_ioctx_t io, rados_snap_t * snaps, int maxlen)
213 int rados_ioctx_snap_get_stamp(rados_ioctx_t io, rados_snap_t id, time_t * t)
215 int rados_lock_exclusive(rados_ioctx_t io, const char * oid, const char * name,
216 const char * cookie, const char * desc,
217 timeval * duration, uint8_t flags)
218 int rados_lock_shared(rados_ioctx_t io, const char * o, const char * name,
219 const char * cookie, const char * tag, const char * desc,
220 timeval * duration, uint8_t flags)
221 int rados_unlock(rados_ioctx_t io, const char * o, const char * name, const char * cookie)
223 rados_write_op_t rados_create_write_op()
224 void rados_release_write_op(rados_write_op_t write_op)
226 rados_read_op_t rados_create_read_op()
227 void rados_release_read_op(rados_read_op_t read_op)
229 int rados_aio_create_completion(void * cb_arg, rados_callback_t cb_complete, rados_callback_t cb_safe, rados_completion_t * pc)
230 void rados_aio_release(rados_completion_t c)
231 int rados_aio_stat(rados_ioctx_t io, const char *oid, rados_completion_t completion, uint64_t *psize, time_t *pmtime)
232 int rados_aio_write(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * buf, size_t len, uint64_t off)
233 int rados_aio_append(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * buf, size_t len)
234 int rados_aio_write_full(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * buf, size_t len)
235 int rados_aio_remove(rados_ioctx_t io, const char * oid, rados_completion_t completion)
236 int rados_aio_read(rados_ioctx_t io, const char * oid, rados_completion_t completion, char * buf, size_t len, uint64_t off)
237 int rados_aio_flush(rados_ioctx_t io)
239 int rados_aio_get_return_value(rados_completion_t c)
240 int rados_aio_wait_for_complete_and_cb(rados_completion_t c)
241 int rados_aio_wait_for_safe_and_cb(rados_completion_t c)
242 int rados_aio_wait_for_complete(rados_completion_t c)
243 int rados_aio_wait_for_safe(rados_completion_t c)
244 int rados_aio_is_complete(rados_completion_t c)
245 int rados_aio_is_safe(rados_completion_t c)
247 int rados_exec(rados_ioctx_t io, const char * oid, const char * cls, const char * method,
248 const char * in_buf, size_t in_len, char * buf, size_t out_len)
249 int rados_aio_exec(rados_ioctx_t io, const char * oid, rados_completion_t completion, const char * cls, const char * method,
250 const char * in_buf, size_t in_len, char * buf, size_t out_len)
252 int rados_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, const char * oid, time_t * mtime, int flags)
253 int rados_aio_write_op_operate(rados_write_op_t write_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, time_t *mtime, int flags)
254 void rados_write_op_omap_set(rados_write_op_t write_op, const char * const* keys, const char * const* vals, const size_t * lens, size_t num)
255 void rados_write_op_omap_rm_keys(rados_write_op_t write_op, const char * const* keys, size_t keys_len)
256 void rados_write_op_omap_clear(rados_write_op_t write_op)
257 void rados_write_op_set_flags(rados_write_op_t write_op, int flags)
259 void rados_write_op_create(rados_write_op_t write_op, int exclusive, const char *category)
260 void rados_write_op_append(rados_write_op_t write_op, const char *buffer, size_t len)
261 void rados_write_op_write_full(rados_write_op_t write_op, const char *buffer, size_t len)
262 void rados_write_op_write(rados_write_op_t write_op, const char *buffer, size_t len, uint64_t offset)
263 void rados_write_op_remove(rados_write_op_t write_op)
264 void rados_write_op_truncate(rados_write_op_t write_op, uint64_t offset)
265 void rados_write_op_zero(rados_write_op_t write_op, uint64_t offset, uint64_t len)
267 void rados_read_op_omap_get_vals(rados_read_op_t read_op, const char * start_after, const char * filter_prefix, uint64_t max_return, rados_omap_iter_t * iter, int * prval)
268 void rados_read_op_omap_get_keys(rados_read_op_t read_op, const char * start_after, uint64_t max_return, rados_omap_iter_t * iter, int * prval)
269 void rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op, const char * const* keys, size_t keys_len, rados_omap_iter_t * iter, int * prval)
270 int rados_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, const char * oid, int flags)
271 int rados_aio_read_op_operate(rados_read_op_t read_op, rados_ioctx_t io, rados_completion_t completion, const char *oid, int flags)
272 void rados_read_op_set_flags(rados_read_op_t read_op, int flags)
273 int rados_omap_get_next(rados_omap_iter_t iter, const char * const* key, const char * const* val, size_t * len)
274 void rados_omap_get_end(rados_omap_iter_t iter)
277 LIBRADOS_OP_FLAG_EXCL = _LIBRADOS_OP_FLAG_EXCL
278 LIBRADOS_OP_FLAG_FAILOK = _LIBRADOS_OP_FLAG_FAILOK
279 LIBRADOS_OP_FLAG_FADVISE_RANDOM = _LIBRADOS_OP_FLAG_FADVISE_RANDOM
280 LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL = _LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
281 LIBRADOS_OP_FLAG_FADVISE_WILLNEED = _LIBRADOS_OP_FLAG_FADVISE_WILLNEED
282 LIBRADOS_OP_FLAG_FADVISE_DONTNEED = _LIBRADOS_OP_FLAG_FADVISE_DONTNEED
283 LIBRADOS_OP_FLAG_FADVISE_NOCACHE = _LIBRADOS_OP_FLAG_FADVISE_NOCACHE
285 LIBRADOS_SNAP_HEAD = _LIBRADOS_SNAP_HEAD
287 LIBRADOS_OPERATION_NOFLAG = _LIBRADOS_OPERATION_NOFLAG
288 LIBRADOS_OPERATION_BALANCE_READS = _LIBRADOS_OPERATION_BALANCE_READS
289 LIBRADOS_OPERATION_LOCALIZE_READS = _LIBRADOS_OPERATION_LOCALIZE_READS
290 LIBRADOS_OPERATION_ORDER_READS_WRITES = _LIBRADOS_OPERATION_ORDER_READS_WRITES
291 LIBRADOS_OPERATION_IGNORE_CACHE = _LIBRADOS_OPERATION_IGNORE_CACHE
292 LIBRADOS_OPERATION_SKIPRWLOCKS = _LIBRADOS_OPERATION_SKIPRWLOCKS
293 LIBRADOS_OPERATION_IGNORE_OVERLAY = _LIBRADOS_OPERATION_IGNORE_OVERLAY
295 LIBRADOS_ALL_NSPACES = _LIBRADOS_ALL_NSPACES.decode('utf-8')
297 LIBRADOS_CREATE_EXCLUSIVE = _LIBRADOS_CREATE_EXCLUSIVE
298 LIBRADOS_CREATE_IDEMPOTENT = _LIBRADOS_CREATE_IDEMPOTENT
300 ANONYMOUS_AUID = 0xffffffffffffffff
304 class Error(Exception):
305 """ `Error` class, derived from `Exception` """
309 class InvalidArgumentError(Error):
313 class OSError(Error):
314 """ `OSError` class, derived from `Error` """
315 def __init__(self, errno, strerror):
317 self.strerror = strerror
320 return '[Errno {0}] {1}'.format(self.errno, self.strerror)
323 class InterruptedOrTimeoutError(OSError):
324 """ `InterruptedOrTimeoutError` class, derived from `OSError` """
328 class PermissionError(OSError):
329 """ `PermissionError` class, derived from `OSError` """
333 class PermissionDeniedError(OSError):
334 """ deal with EACCES related. """
338 class ObjectNotFound(OSError):
339 """ `ObjectNotFound` class, derived from `OSError` """
343 class NoData(OSError):
344 """ `NoData` class, derived from `OSError` """
348 class ObjectExists(OSError):
349 """ `ObjectExists` class, derived from `OSError` """
353 class ObjectBusy(OSError):
354 """ `ObjectBusy` class, derived from `IOError` """
358 class IOError(OSError):
359 """ `ObjectBusy` class, derived from `OSError` """
363 class NoSpace(OSError):
364 """ `NoSpace` class, derived from `OSError` """
368 class RadosStateError(Error):
369 """ `RadosStateError` class, derived from `Error` """
373 class IoctxStateError(Error):
374 """ `IoctxStateError` class, derived from `Error` """
378 class ObjectStateError(Error):
379 """ `ObjectStateError` class, derived from `Error` """
383 class LogicError(Error):
384 """ `` class, derived from `Error` """
388 class TimedOut(OSError):
389 """ `TimedOut` class, derived from `OSError` """
393 IF UNAME_SYSNAME == "FreeBSD":
394 cdef errno_to_exception = {
395 errno.EPERM : PermissionError,
396 errno.ENOENT : ObjectNotFound,
398 errno.ENOSPC : NoSpace,
399 errno.EEXIST : ObjectExists,
400 errno.EBUSY : ObjectBusy,
401 errno.ENOATTR : NoData,
402 errno.EINTR : InterruptedOrTimeoutError,
403 errno.ETIMEDOUT : TimedOut,
404 errno.EACCES : PermissionDeniedError,
405 errno.EINVAL : InvalidArgumentError,
408 cdef errno_to_exception = {
409 errno.EPERM : PermissionError,
410 errno.ENOENT : ObjectNotFound,
412 errno.ENOSPC : NoSpace,
413 errno.EEXIST : ObjectExists,
414 errno.EBUSY : ObjectBusy,
415 errno.ENODATA : NoData,
416 errno.EINTR : InterruptedOrTimeoutError,
417 errno.ETIMEDOUT : TimedOut,
418 errno.EACCES : PermissionDeniedError,
419 errno.EINVAL : InvalidArgumentError,
423 cdef make_ex(ret, msg):
425 Translate a librados return code into an exception.
427 :param ret: the return code
429 :param msg: the error message to use
431 :returns: a subclass of :class:`Error`
434 if ret in errno_to_exception:
435 return errno_to_exception[ret](ret, msg)
437 return Error(ret, msg + (": error code %d" % ret))
440 # helper to specify an optional argument, where in addition to `cls`, `None`
446 # validate argument types of an instance method
447 # kwargs is an un-ordered dict, so use args instead
448 def requires(*types):
449 def is_type_of(v, t):
453 return isinstance(v, t)
455 def check_type(val, arg_name, arg_type):
456 if isinstance(arg_type, tuple):
457 if any(is_type_of(val, t) for t in arg_type):
459 type_names = ' or '.join('None' if t is None else t.__name__
461 raise TypeError('%s must be %s' % (arg_name, type_names))
463 if is_type_of(val, arg_type):
465 assert(arg_type is not None)
466 raise TypeError('%s must be %s' % (arg_name, arg_type.__name__))
469 # FIXME(sileht): this stop with
470 # AttributeError: 'method_descriptor' object has no attribute '__module__'
472 def validate_func(*args, **kwargs):
473 # ignore the `self` arg
474 pos_args = zip(args[1:], types)
475 named_args = ((kwargs[name], (name, spec)) for name, spec in types
477 for arg_val, (arg_name, arg_type) in chain(pos_args, named_args):
478 check_type(arg_val, arg_name, arg_type)
479 return f(*args, **kwargs)
484 def cstr(val, name, encoding="utf-8", opt=False):
486 Create a byte string from a Python string
488 :param basestring val: Python string
489 :param str name: Name of the string parameter, for exceptions
490 :param str encoding: Encoding to use
491 :param bool opt: If True, None is allowed
493 :raises: :class:`InvalidArgument`
495 if opt and val is None:
497 if isinstance(val, bytes):
499 elif isinstance(val, unicode):
500 return val.encode(encoding)
502 raise TypeError('%s must be a string' % name)
505 def cstr_list(list_str, name, encoding="utf-8"):
506 return [cstr(s, name) for s in list_str]
509 def decode_cstr(val, encoding="utf-8"):
511 Decode a byte string into a Python string.
513 :param bytes val: byte string
514 :rtype: unicode or None
519 return val.decode(encoding)
522 cdef char* opt_str(s) except? NULL:
528 cdef void* realloc_chk(void* ptr, size_t size) except NULL:
529 cdef void *ret = realloc(ptr, size)
531 raise MemoryError("realloc failed")
535 cdef size_t * to_csize_t_array(list_int):
536 cdef size_t *ret = <size_t *>malloc(len(list_int) * sizeof(size_t))
538 raise MemoryError("malloc failed")
539 for i in xrange(len(list_int)):
540 ret[i] = <size_t>list_int[i]
544 cdef char ** to_bytes_array(list_bytes):
545 cdef char **ret = <char **>malloc(len(list_bytes) * sizeof(char *))
547 raise MemoryError("malloc failed")
548 for i in xrange(len(list_bytes)):
549 ret[i] = <char *>list_bytes[i]
554 cdef int __monitor_callback(void *arg, const char *line, const char *who,
555 uint64_t sec, uint64_t nsec, uint64_t seq,
556 const char *level, const char *msg) with gil:
557 cdef object cb_info = <object>arg
558 cb_info[0](cb_info[1], line, who, sec, nsec, seq, level, msg)
561 cdef int __monitor_callback2(void *arg, const char *line, const char *who,
563 uint64_t sec, uint64_t nsec, uint64_t seq,
564 const char *level, const char *msg) with gil:
565 cdef object cb_info = <object>arg
566 cb_info[0](cb_info[1], line, name, who, sec, nsec, seq, level, msg)
570 class Version(object):
571 """ Version information """
572 def __init__(self, major, minor, extra):
578 return "%d.%d.%d" % (self.major, self.minor, self.extra)
581 cdef class Rados(object):
582 """This class wraps librados functions"""
583 # NOTE(sileht): attributes declared in .pyd
585 def __init__(self, *args, **kwargs):
587 self.__setup(*args, **kwargs)
589 @requires(('rados_id', opt(str_type)), ('name', opt(str_type)), ('clustername', opt(str_type)),
590 ('conffile', opt(str_type)))
591 def __setup(self, rados_id=None, name=None, clustername=None,
592 conf_defaults=None, conffile=None, conf=None, flags=0,
594 self.monitor_callback = None
595 self.monitor_callback2 = None
596 self.parsed_args = []
597 self.conf_defaults = conf_defaults
598 self.conffile = conffile
599 self.rados_id = rados_id
601 if rados_id and name:
602 raise Error("Rados(): can't supply both rados_id and name")
604 name = 'client.' + rados_id
606 name = 'client.admin'
607 if clustername is None:
610 name = cstr(name, 'name')
611 clustername = cstr(clustername, 'clustername')
614 char *_clustername = clustername
619 # Unpack void* (aka rados_config_t) from capsule
620 rados_config = <rados_config_t> PyCapsule_GetPointer(context, NULL)
622 ret = rados_create_with_context(&self.cluster, rados_config)
625 ret = rados_create2(&self.cluster, _clustername, _name, _flags)
627 raise Error("rados_initialize failed with error code: %d" % ret)
629 self.state = "configuring"
630 # order is important: conf_defaults, then conffile, then conf
632 for key, value in conf_defaults.items():
633 self.conf_set(key, value)
634 if conffile is not None:
635 # read the default conf file when '' is given
638 self.conf_read_file(conffile)
640 for key, value in conf.items():
641 self.conf_set(key, value)
643 def require_state(self, *args):
645 Checks if the Rados object is in a special state
647 :raises: RadosStateError
649 if self.state in args:
651 raise RadosStateError("You cannot perform that operation on a \
652 Rados object in state %s." % self.state)
656 Disconnects from the cluster. Call this explicitly when a
657 Rados.connect()ed object is no longer used.
659 if self.state != "shutdown":
661 rados_shutdown(self.cluster)
662 self.state = "shutdown"
668 def __exit__(self, type_, value, traceback):
674 Get the version number of the ``librados`` C library.
676 :returns: a tuple of ``(major, minor, extra)`` components of the
683 rados_version(&major, &minor, &extra)
684 return Version(major, minor, extra)
686 @requires(('path', opt(str_type)))
687 def conf_read_file(self, path=None):
689 Configure the cluster handle using a Ceph config file.
691 :param path: path to the config file
694 self.require_state("configuring", "connected")
695 path = cstr(path, 'path', opt=True)
697 char *_path = opt_str(path)
699 ret = rados_conf_read_file(self.cluster, _path)
701 raise make_ex(ret, "error calling conf_read_file")
703 def conf_parse_argv(self, args):
705 Parse known arguments from args, and remove; returned
706 args contain only those unknown to ceph
708 self.require_state("configuring", "connected")
712 cargs = cstr_list(args, 'args')
714 int _argc = len(args)
715 char **_argv = to_bytes_array(cargs)
716 char **_remargv = NULL
719 _remargv = <char **>malloc(_argc * sizeof(char *))
721 ret = rados_conf_parse_argv_remainder(self.cluster, _argc,
723 <const char**>_remargv)
725 raise make_ex(ret, "error calling conf_parse_argv_remainder")
727 # _remargv was allocated with fixed argc; collapse return
728 # list to eliminate any missing args
729 retargs = [decode_cstr(a) for a in _remargv[:_argc]
731 self.parsed_args = args
737 def conf_parse_env(self, var='CEPH_ARGS'):
739 Parse known arguments from an environment variable, normally
742 self.require_state("configuring", "connected")
746 var = cstr(var, 'var')
750 ret = rados_conf_parse_env(self.cluster, _var)
752 raise make_ex(ret, "error calling conf_parse_env")
754 @requires(('option', str_type))
755 def conf_get(self, option):
757 Get the value of a configuration option
759 :param option: which option to read
762 :returns: str - value of the option or None
763 :raises: :class:`TypeError`
765 self.require_state("configuring", "connected")
766 option = cstr(option, 'option')
768 char *_option = option
774 ret_buf = <char *>realloc_chk(ret_buf, length)
776 ret = rados_conf_get(self.cluster, _option, ret_buf, length)
778 return decode_cstr(ret_buf)
779 elif ret == -errno.ENAMETOOLONG:
781 elif ret == -errno.ENOENT:
784 raise make_ex(ret, "error calling conf_get")
788 @requires(('option', str_type), ('val', str_type))
789 def conf_set(self, option, val):
791 Set the value of a configuration option
793 :param option: which option to set
795 :param option: value of the option
798 :raises: :class:`TypeError`, :class:`ObjectNotFound`
800 self.require_state("configuring", "connected")
801 option = cstr(option, 'option')
802 val = cstr(val, 'val')
804 char *_option = option
808 ret = rados_conf_set(self.cluster, _option, _val)
810 raise make_ex(ret, "error calling conf_set")
812 def ping_monitor(self, mon_id):
814 Ping a monitor to assess liveness
816 May be used as a simply way to assess liveness, or to obtain
817 information about the monitor in a simple way even in the
820 :param mon_id: the ID portion of the monitor's name (i.e., mon.<ID>)
822 :returns: the string reply from the monitor
825 self.require_state("configuring", "connected")
827 mon_id = cstr(mon_id, 'mon_id')
829 char *_mon_id = mon_id
834 ret = rados_ping_monitor(self.cluster, _mon_id, &outstr, &outstrlen)
837 raise make_ex(ret, "error calling ping_monitor")
840 my_outstr = outstr[:outstrlen]
841 rados_buffer_free(outstr)
842 return decode_cstr(my_outstr)
844 def connect(self, timeout=0):
846 Connect to the cluster. Use shutdown() to release resources.
848 self.require_state("configuring")
849 # NOTE(sileht): timeout was supported by old python API,
850 # but this is not something available in C API, so ignore
851 # for now and remove it later
853 ret = rados_connect(self.cluster)
855 raise make_ex(ret, "error connecting to the cluster")
856 self.state = "connected"
858 def get_cluster_stats(self):
860 Read usage info about the cluster
862 This tells you total space, space used, space available, and number
863 of objects. These are not updated immediately when data is written,
864 they are eventually consistent.
866 :returns: dict - contains the following keys:
868 - ``kb`` (int) - total space
870 - ``kb_used`` (int) - space used
872 - ``kb_avail`` (int) - free space available
874 - ``num_objects`` (int) - number of objects
878 rados_cluster_stat_t stats
881 ret = rados_cluster_stat(self.cluster, &stats)
885 ret, "Rados.get_cluster_stats(%s): get_stats failed" % self.rados_id)
886 return {'kb': stats.kb,
887 'kb_used': stats.kb_used,
888 'kb_avail': stats.kb_avail,
889 'num_objects': stats.num_objects}
891 @requires(('pool_name', str_type))
892 def pool_exists(self, pool_name):
894 Checks if a given pool exists.
896 :param pool_name: name of the pool to check
899 :raises: :class:`TypeError`, :class:`Error`
900 :returns: bool - whether the pool exists, false otherwise.
902 self.require_state("connected")
904 pool_name = cstr(pool_name, 'pool_name')
906 char *_pool_name = pool_name
909 ret = rados_pool_lookup(self.cluster, _pool_name)
912 elif ret == -errno.ENOENT:
915 raise make_ex(ret, "error looking up pool '%s'" % pool_name)
917 @requires(('pool_name', str_type))
918 def pool_lookup(self, pool_name):
920 Returns a pool's ID based on its name.
922 :param pool_name: name of the pool to look up
925 :raises: :class:`TypeError`, :class:`Error`
926 :returns: int - pool ID, or None if it doesn't exist
928 self.require_state("connected")
929 pool_name = cstr(pool_name, 'pool_name')
931 char *_pool_name = pool_name
934 ret = rados_pool_lookup(self.cluster, _pool_name)
937 elif ret == -errno.ENOENT:
940 raise make_ex(ret, "error looking up pool '%s'" % pool_name)
942 @requires(('pool_id', int))
943 def pool_reverse_lookup(self, pool_id):
945 Returns a pool's name based on its ID.
947 :param pool_id: ID of the pool to look up
950 :raises: :class:`TypeError`, :class:`Error`
951 :returns: string - pool name, or None if it doesn't exist
953 self.require_state("connected")
955 int64_t _pool_id = pool_id
961 name = <char *>realloc_chk(name, size)
963 ret = rados_pool_reverse_lookup(self.cluster, _pool_id, name, size)
966 elif ret != -errno.ERANGE and size <= 4096:
968 elif ret == -errno.ENOENT:
971 raise make_ex(ret, "error reverse looking up pool '%s'" % pool_id)
973 return decode_cstr(name)
978 @requires(('pool_name', str_type), ('auid', opt(int)), ('crush_rule', opt(int)))
979 def create_pool(self, pool_name, auid=None, crush_rule=None):
982 - with default settings: if auid=None and crush_rule=None
983 - owned by a specific auid: auid given and crush_rule=None
984 - with a specific CRUSH rule: if auid=None and crush_rule given
985 - with a specific CRUSH rule and auid: if auid and crush_rule given
987 :param pool_name: name of the pool to create
989 :param auid: the id of the owner of the new pool
991 :param crush_rule: rule to use for placement in the new pool
992 :type crush_rule: int
994 :raises: :class:`TypeError`, :class:`Error`
996 self.require_state("connected")
998 pool_name = cstr(pool_name, 'pool_name')
1000 char *_pool_name = pool_name
1004 if auid is None and crush_rule is None:
1006 ret = rados_pool_create(self.cluster, _pool_name)
1008 _crush_rule = crush_rule
1010 ret = rados_pool_create_with_crush_rule(self.cluster, _pool_name, _crush_rule)
1011 elif crush_rule is None:
1014 ret = rados_pool_create_with_auid(self.cluster, _pool_name, _auid)
1017 _crush_rule = crush_rule
1019 ret = rados_pool_create_with_all(self.cluster, _pool_name, _auid, _crush_rule)
1021 raise make_ex(ret, "error creating pool '%s'" % pool_name)
1023 @requires(('pool_id', int))
1024 def get_pool_base_tier(self, pool_id):
1028 :returns: base pool, or pool_id if tiering is not configured for the pool
1030 self.require_state("connected")
1032 int64_t base_tier = 0
1033 int64_t _pool_id = pool_id
1036 ret = rados_pool_get_base_tier(self.cluster, _pool_id, &base_tier)
1038 raise make_ex(ret, "get_pool_base_tier(%d)" % pool_id)
1039 return int(base_tier)
1041 @requires(('pool_name', str_type))
1042 def delete_pool(self, pool_name):
1044 Delete a pool and all data inside it.
1046 The pool is removed from the cluster immediately,
1047 but the actual data is deleted in the background.
1049 :param pool_name: name of the pool to delete
1050 :type pool_name: str
1052 :raises: :class:`TypeError`, :class:`Error`
1054 self.require_state("connected")
1056 pool_name = cstr(pool_name, 'pool_name')
1058 char *_pool_name = pool_name
1061 ret = rados_pool_delete(self.cluster, _pool_name)
1063 raise make_ex(ret, "error deleting pool '%s'" % pool_name)
1065 @requires(('pool_id', int))
1066 def get_inconsistent_pgs(self, pool_id):
1068 List inconsistent placement groups in the given pool
1070 :param pool_id: ID of the pool in which PGs are listed
1072 :returns: list - inconsistent placement groups
1074 self.require_state("connected")
1076 int64_t pool = pool_id
1082 pgs = <char *>realloc_chk(pgs, size);
1084 ret = rados_inconsistent_pg_list(self.cluster, pool,
1091 raise make_ex(ret, "error calling inconsistent_pg_list")
1092 return [pg for pg in decode_cstr(pgs[:ret]).split('\0') if pg]
1096 def list_pools(self):
1098 Gets a list of pool names.
1100 :returns: list - of pool names.
1102 self.require_state("connected")
1105 char *c_names = NULL
1109 c_names = <char *>realloc_chk(c_names, size)
1111 ret = rados_pool_list(self.cluster, c_names, size)
1116 return [name for name in decode_cstr(c_names[:ret]).split('\0')
1123 Get the fsid of the cluster as a hexadecimal string.
1125 :raises: :class:`Error`
1126 :returns: str - cluster fsid
1128 self.require_state("connected")
1132 PyObject* ret_s = NULL
1134 ret_s = PyBytes_FromStringAndSize(NULL, buf_len)
1136 ret_buf = PyBytes_AsString(ret_s)
1138 ret = rados_cluster_fsid(self.cluster, ret_buf, buf_len)
1140 raise make_ex(ret, "error getting cluster fsid")
1141 if ret != <int>buf_len:
1142 _PyBytes_Resize(&ret_s, ret)
1143 return <object>ret_s
1145 # We DECREF unconditionally: the cast to object above will have
1146 # INCREFed if necessary. This also takes care of exceptions,
1147 # including if _PyString_Resize fails (that will free the string
1148 # itself and set ret_s to NULL, hence XDECREF).
1149 ref.Py_XDECREF(ret_s)
1151 @requires(('ioctx_name', str_type))
1152 def open_ioctx(self, ioctx_name):
1154 Create an io context
1156 The io context allows you to perform operations within a particular
1159 :param ioctx_name: name of the pool
1160 :type ioctx_name: str
1162 :raises: :class:`TypeError`, :class:`Error`
1163 :returns: Ioctx - Rados Ioctx object
1165 self.require_state("connected")
1166 ioctx_name = cstr(ioctx_name, 'ioctx_name')
1169 char *_ioctx_name = ioctx_name
1171 ret = rados_ioctx_create(self.cluster, _ioctx_name, &ioctx)
1173 raise make_ex(ret, "error opening pool '%s'" % ioctx_name)
1174 io = Ioctx(ioctx_name)
1178 def mon_command(self, cmd, inbuf, timeout=0, target=None):
1180 mon_command[_target](cmd, inbuf, outbuf, outbuflen, outs, outslen)
1181 returns (int ret, string outbuf, string outs)
1183 # NOTE(sileht): timeout is ignored because C API doesn't provide
1184 # timeout argument, but we keep it for backward compat with old python binding
1186 self.require_state("connected")
1187 cmd = cstr_list(cmd, 'c')
1189 if isinstance(target, int):
1190 # NOTE(sileht): looks weird but test_monmap_dump pass int
1191 target = str(target)
1193 target = cstr(target, 'target', opt=True)
1194 inbuf = cstr(inbuf, 'inbuf')
1197 char *_target = opt_str(target)
1198 char **_cmd = to_bytes_array(cmd)
1199 size_t _cmdlen = len(cmd)
1201 char *_inbuf = inbuf
1202 size_t _inbuf_len = len(inbuf)
1212 ret = rados_mon_command_target(self.cluster, _target,
1213 <const char **>_cmd, _cmdlen,
1214 <const char*>_inbuf, _inbuf_len,
1215 &_outbuf, &_outbuf_len,
1219 ret = rados_mon_command(self.cluster,
1220 <const char **>_cmd, _cmdlen,
1221 <const char*>_inbuf, _inbuf_len,
1222 &_outbuf, &_outbuf_len,
1225 my_outs = decode_cstr(_outs[:_outs_len])
1226 my_outbuf = _outbuf[:_outbuf_len]
1228 rados_buffer_free(_outs)
1230 rados_buffer_free(_outbuf)
1231 return (ret, my_outbuf, my_outs)
1235 def osd_command(self, osdid, cmd, inbuf, timeout=0):
1237 osd_command(osdid, cmd, inbuf, outbuf, outbuflen, outs, outslen)
1238 returns (int ret, string outbuf, string outs)
1240 # NOTE(sileht): timeout is ignored because C API doesn't provide
1241 # timeout argument, but we keep it for backward compat with old python binding
1242 self.require_state("connected")
1244 cmd = cstr_list(cmd, 'cmd')
1245 inbuf = cstr(inbuf, 'inbuf')
1249 char **_cmd = to_bytes_array(cmd)
1250 size_t _cmdlen = len(cmd)
1252 char *_inbuf = inbuf
1253 size_t _inbuf_len = len(inbuf)
1262 ret = rados_osd_command(self.cluster, _osdid,
1263 <const char **>_cmd, _cmdlen,
1264 <const char*>_inbuf, _inbuf_len,
1265 &_outbuf, &_outbuf_len,
1268 my_outs = decode_cstr(_outs[:_outs_len])
1269 my_outbuf = _outbuf[:_outbuf_len]
1271 rados_buffer_free(_outs)
1273 rados_buffer_free(_outbuf)
1274 return (ret, my_outbuf, my_outs)
1278 def mgr_command(self, cmd, inbuf, timeout=0):
1280 returns (int ret, string outbuf, string outs)
1282 # NOTE(sileht): timeout is ignored because C API doesn't provide
1283 # timeout argument, but we keep it for backward compat with old python binding
1284 self.require_state("connected")
1286 cmd = cstr_list(cmd, 'cmd')
1287 inbuf = cstr(inbuf, 'inbuf')
1290 char **_cmd = to_bytes_array(cmd)
1291 size_t _cmdlen = len(cmd)
1293 char *_inbuf = inbuf
1294 size_t _inbuf_len = len(inbuf)
1303 ret = rados_mgr_command(self.cluster,
1304 <const char **>_cmd, _cmdlen,
1305 <const char*>_inbuf, _inbuf_len,
1306 &_outbuf, &_outbuf_len,
1309 my_outs = decode_cstr(_outs[:_outs_len])
1310 my_outbuf = _outbuf[:_outbuf_len]
1312 rados_buffer_free(_outs)
1314 rados_buffer_free(_outbuf)
1315 return (ret, my_outbuf, my_outs)
1319 def pg_command(self, pgid, cmd, inbuf, timeout=0):
1321 pg_command(pgid, cmd, inbuf, outbuf, outbuflen, outs, outslen)
1322 returns (int ret, string outbuf, string outs)
1324 # NOTE(sileht): timeout is ignored because C API doesn't provide
1325 # timeout argument, but we keep it for backward compat with old python binding
1326 self.require_state("connected")
1328 pgid = cstr(pgid, 'pgid')
1329 cmd = cstr_list(cmd, 'cmd')
1330 inbuf = cstr(inbuf, 'inbuf')
1334 char **_cmd = to_bytes_array(cmd)
1335 size_t _cmdlen = len(cmd)
1337 char *_inbuf = inbuf
1338 size_t _inbuf_len = len(inbuf)
1347 ret = rados_pg_command(self.cluster, _pgid,
1348 <const char **>_cmd, _cmdlen,
1349 <const char *>_inbuf, _inbuf_len,
1350 &_outbuf, &_outbuf_len,
1353 my_outs = decode_cstr(_outs[:_outs_len])
1354 my_outbuf = _outbuf[:_outbuf_len]
1356 rados_buffer_free(_outs)
1358 rados_buffer_free(_outbuf)
1359 return (ret, my_outbuf, my_outs)
1363 def wait_for_latest_osdmap(self):
1364 self.require_state("connected")
1366 ret = rados_wait_for_latest_osdmap(self.cluster)
1369 def blacklist_add(self, client_address, expire_seconds=0):
1371 Blacklist a client from the OSDs
1373 :param client_address: client address
1374 :type client_address: str
1375 :param expire_seconds: number of seconds to blacklist
1376 :type expire_seconds: int
1378 :raises: :class:`Error`
1380 self.require_state("connected")
1381 client_address = cstr(client_address, 'client_address')
1383 uint32_t _expire_seconds = expire_seconds
1384 char *_client_address = client_address
1387 ret = rados_blacklist_add(self.cluster, _client_address, _expire_seconds)
1389 raise make_ex(ret, "error blacklisting client '%s'" % client_address)
1391 def monitor_log(self, level, callback, arg):
1392 if level not in MONITOR_LEVELS:
1393 raise LogicError("invalid monitor level " + level)
1394 if callback is not None and not callable(callback):
1395 raise LogicError("callback must be a callable function or None")
1397 level = cstr(level, 'level')
1398 cdef char *_level = level
1400 if callback is None:
1402 r = rados_monitor_log(self.cluster, <const char*>_level, NULL, NULL)
1403 self.monitor_callback = None
1404 self.monitor_callback2 = None
1407 cb = (callback, arg)
1408 cdef PyObject* _arg = <PyObject*>cb
1410 r = rados_monitor_log(self.cluster, <const char*>_level,
1411 <rados_log_callback_t>&__monitor_callback, _arg)
1414 raise make_ex(r, 'error calling rados_monitor_log')
1415 # NOTE(sileht): Prevents the callback method from being garbage collected
1416 self.monitor_callback = cb
1417 self.monitor_callback2 = None
1419 def monitor_log2(self, level, callback, arg):
1420 if level not in MONITOR_LEVELS:
1421 raise LogicError("invalid monitor level " + level)
1422 if callback is not None and not callable(callback):
1423 raise LogicError("callback must be a callable function or None")
1425 level = cstr(level, 'level')
1426 cdef char *_level = level
1428 if callback is None:
1430 r = rados_monitor_log2(self.cluster, <const char*>_level, NULL, NULL)
1431 self.monitor_callback = None
1432 self.monitor_callback2 = None
1435 cb = (callback, arg)
1436 cdef PyObject* _arg = <PyObject*>cb
1438 r = rados_monitor_log2(self.cluster, <const char*>_level,
1439 <rados_log_callback2_t>&__monitor_callback2, _arg)
1442 raise make_ex(r, 'error calling rados_monitor_log')
1443 # NOTE(sileht): Prevents the callback method from being garbage collected
1444 self.monitor_callback = None
1445 self.monitor_callback2 = cb
1448 cdef class OmapIterator(object):
1451 cdef public Ioctx ioctx
1452 cdef rados_omap_iter_t ctx
1454 def __cinit__(self, Ioctx ioctx):
1462 Get the next key-value pair in the object
1463 :returns: next rados.OmapItem
1471 ret = rados_omap_get_next(self.ctx, &key_, &val_, &len_)
1474 raise make_ex(ret, "error iterating over the omap")
1476 raise StopIteration()
1477 key = decode_cstr(key_)
1483 def __dealloc__(self):
1485 rados_omap_get_end(self.ctx)
1488 cdef class ObjectIterator(object):
1489 """rados.Ioctx Object iterator"""
1491 cdef rados_list_ctx_t ctx
1493 cdef public object ioctx
1495 def __cinit__(self, Ioctx ioctx):
1499 ret = rados_nobjects_list_open(ioctx.io, &self.ctx)
1501 raise make_ex(ret, "error iterating over the objects in ioctx '%s'"
1509 Get the next object name and locator in the pool
1511 :raises: StopIteration
1512 :returns: next rados.Ioctx Object
1515 const char *key_ = NULL
1516 const char *locator_ = NULL
1517 const char *nspace_ = NULL
1520 ret = rados_nobjects_list_next(self.ctx, &key_, &locator_, &nspace_)
1523 raise StopIteration()
1525 key = decode_cstr(key_)
1526 locator = decode_cstr(locator_) if locator_ != NULL else None
1527 nspace = decode_cstr(nspace_) if nspace_ != NULL else None
1528 return Object(self.ioctx, key, locator, nspace)
1530 def __dealloc__(self):
1532 rados_nobjects_list_close(self.ctx)
1535 cdef class XattrIterator(object):
1536 """Extended attribute iterator"""
1538 cdef rados_xattrs_iter_t it
1541 cdef public Ioctx ioctx
1542 cdef public object oid
1544 def __cinit__(self, Ioctx ioctx, oid):
1546 self.oid = cstr(oid, 'oid')
1547 self._oid = self.oid
1550 ret = rados_getxattrs(ioctx.io, self._oid, &self.it)
1552 raise make_ex(ret, "Failed to get rados xattrs for object %r" % oid)
1559 Get the next xattr on the object
1561 :raises: StopIteration
1562 :returns: pair - of name and value of the next Xattr
1565 const char *name_ = NULL
1566 const char *val_ = NULL
1570 ret = rados_getxattrs_next(self.it, &name_, &val_, &len_)
1572 raise make_ex(ret, "error iterating over the extended attributes \
1573 in '%s'" % self.oid)
1575 raise StopIteration()
1576 name = decode_cstr(name_)
1580 def __dealloc__(self):
1582 rados_getxattrs_end(self.it)
1585 cdef class SnapIterator(object):
1586 """Snapshot iterator"""
1588 cdef public Ioctx ioctx
1590 cdef rados_snap_t *snaps
1594 def __cinit__(self, Ioctx ioctx):
1596 # We don't know how big a buffer we need until we've called the
1597 # function. So use the exponential doubling strategy.
1598 cdef int num_snaps = 10
1600 self.snaps = <rados_snap_t*>realloc_chk(self.snaps,
1602 sizeof(rados_snap_t))
1605 ret = rados_ioctx_snap_list(ioctx.io, self.snaps, num_snaps)
1609 elif ret != -errno.ERANGE:
1610 raise make_ex(ret, "error calling rados_snap_list for \
1611 ioctx '%s'" % self.ioctx.name)
1612 num_snaps = num_snaps * 2
1620 Get the next Snapshot
1622 :raises: :class:`Error`, StopIteration
1623 :returns: Snap - next snapshot
1625 if self.cur_snap >= self.max_snap:
1629 rados_snap_t snap_id = self.snaps[self.cur_snap]
1635 name = <char *>realloc_chk(name, name_len)
1637 ret = rados_ioctx_snap_get_name(self.ioctx.io, snap_id, name, name_len)
1640 elif ret != -errno.ERANGE:
1641 raise make_ex(ret, "rados_snap_get_name error")
1643 name_len = name_len * 2
1645 snap = Snap(self.ioctx, decode_cstr(name[:name_len]).rstrip('\0'), snap_id)
1646 self.cur_snap = self.cur_snap + 1
1652 cdef class Snap(object):
1653 """Snapshot object"""
1654 cdef public Ioctx ioctx
1655 cdef public object name
1657 # NOTE(sileht): old API was storing the ctypes object
1658 # instead of the value ....
1659 cdef public rados_snap_t snap_id
1661 def __cinit__(self, Ioctx ioctx, object name, rados_snap_t snap_id):
1664 self.snap_id = snap_id
1667 return "rados.Snap(ioctx=%s,name=%s,snap_id=%d)" \
1668 % (str(self.ioctx), self.name, self.snap_id)
1670 def get_timestamp(self):
1672 Find when a snapshot in the current pool occurred
1674 :raises: :class:`Error`
1675 :returns: datetime - the data and time the snapshot was created
1677 cdef time_t snap_time
1680 ret = rados_ioctx_snap_get_stamp(self.ioctx.io, self.snap_id, &snap_time)
1682 raise make_ex(ret, "rados_ioctx_snap_get_stamp error")
1683 return datetime.fromtimestamp(snap_time)
1686 cdef class Completion(object):
1687 """completion object"""
1695 rados_callback_t complete_cb
1696 rados_callback_t safe_cb
1697 rados_completion_t rados_comp
1700 def __cinit__(self, Ioctx ioctx, object oncomplete, object onsafe):
1701 self.oncomplete = oncomplete
1702 self.onsafe = onsafe
1707 Is an asynchronous operation safe?
1709 This does not imply that the safe callback has finished.
1711 :returns: True if the operation is safe
1714 ret = rados_aio_is_safe(self.rados_comp)
1717 def is_complete(self):
1719 Has an asynchronous operation completed?
1721 This does not imply that the safe callback has finished.
1723 :returns: True if the operation is completed
1726 ret = rados_aio_is_complete(self.rados_comp)
1729 def wait_for_safe(self):
1731 Wait for an asynchronous operation to be marked safe
1733 This does not imply that the safe callback has finished.
1736 rados_aio_wait_for_safe(self.rados_comp)
1738 def wait_for_complete(self):
1740 Wait for an asynchronous operation to complete
1742 This does not imply that the complete callback has finished.
1745 rados_aio_wait_for_complete(self.rados_comp)
1747 def wait_for_safe_and_cb(self):
1749 Wait for an asynchronous operation to be marked safe and for
1750 the safe callback to have returned
1753 rados_aio_wait_for_safe_and_cb(self.rados_comp)
1755 def wait_for_complete_and_cb(self):
1757 Wait for an asynchronous operation to complete and for the
1758 complete callback to have returned
1760 :returns: whether the operation is completed
1763 ret = rados_aio_wait_for_complete_and_cb(self.rados_comp)
1766 def get_return_value(self):
1768 Get the return value of an asychronous operation
1770 The return value is set when the operation is complete or safe,
1771 whichever comes first.
1773 :returns: int - return value of the operation
1776 ret = rados_aio_get_return_value(self.rados_comp)
1779 def __dealloc__(self):
1781 Release a completion
1783 Call this when you no longer need the completion. It may not be
1784 freed immediately if the operation is not acked and committed.
1786 ref.Py_XDECREF(self.buf)
1788 if self.rados_comp != NULL:
1790 rados_aio_release(self.rados_comp)
1791 self.rados_comp = NULL
1793 def _complete(self):
1794 self.oncomplete(self)
1795 with self.ioctx.lock:
1797 self.ioctx.complete_completions.remove(self)
1801 with self.ioctx.lock:
1803 self.ioctx.safe_completions.remove(self)
1806 with self.ioctx.lock:
1808 self.ioctx.complete_completions.remove(self)
1810 self.ioctx.safe_completions.remove(self)
1813 class OpCtx(object):
1814 def __enter__(self):
1815 return self.create()
1817 def __exit__(self, type, msg, traceback):
1821 cdef class WriteOp(object):
1822 cdef rados_write_op_t write_op
1826 self.write_op = rados_create_write_op()
1831 rados_release_write_op(self.write_op)
1833 @requires(('exclusive', opt(int)))
1834 def new(self, exclusive=None):
1840 int _exclusive = exclusive
1843 rados_write_op_create(self.write_op, _exclusive, NULL)
1851 rados_write_op_remove(self.write_op)
1853 @requires(('flags', int))
1854 def set_flags(self, flags=LIBRADOS_OPERATION_NOFLAG):
1856 Set flags for the last operation added to this write_op.
1857 :para flags: flags to apply to the last operation
1865 rados_write_op_set_flags(self.write_op, _flags)
1867 @requires(('to_write', bytes))
1868 def append(self, to_write):
1870 Append data to an object synchronously
1871 :param to_write: data to write
1872 :type to_write: bytes
1876 char *_to_write = to_write
1877 size_t length = len(to_write)
1880 rados_write_op_append(self.write_op, _to_write, length)
1882 @requires(('to_write', bytes))
1883 def write_full(self, to_write):
1885 Write whole object, atomically replacing it.
1886 :param to_write: data to write
1887 :type to_write: bytes
1891 char *_to_write = to_write
1892 size_t length = len(to_write)
1895 rados_write_op_write_full(self.write_op, _to_write, length)
1897 @requires(('to_write', bytes), ('offset', int))
1898 def write(self, to_write, offset=0):
1901 :param to_write: data to write
1902 :type to_write: bytes
1903 :param offset: byte offset in the object to begin writing at
1908 char *_to_write = to_write
1909 size_t length = len(to_write)
1910 uint64_t _offset = offset
1913 rados_write_op_write(self.write_op, _to_write, length, _offset)
1915 @requires(('offset', int), ('length', int))
1916 def zero(self, offset, length):
1918 Zero part of an object.
1919 :param offset: byte offset in the object to begin writing at
1921 :param offset: number of zero to write
1926 size_t _length = length
1927 uint64_t _offset = offset
1930 rados_write_op_zero(self.write_op, _length, _offset)
1932 @requires(('offset', int))
1933 def truncate(self, offset):
1936 :param offset: byte offset in the object to begin truncating at
1941 uint64_t _offset = offset
1944 rados_write_op_truncate(self.write_op, _offset)
1947 class WriteOpCtx(WriteOp, OpCtx):
1948 """write operation context manager"""
1951 cdef class ReadOp(object):
1952 cdef rados_read_op_t read_op
1956 self.read_op = rados_create_read_op()
1961 rados_release_read_op(self.read_op)
1963 @requires(('flags', int))
1964 def set_flags(self, flags=LIBRADOS_OPERATION_NOFLAG):
1966 Set flags for the last operation added to this read_op.
1967 :para flags: flags to apply to the last operation
1975 rados_read_op_set_flags(self.read_op, _flags)
1978 class ReadOpCtx(ReadOp, OpCtx):
1979 """read operation context manager"""
1982 cdef int __aio_safe_cb(rados_completion_t completion, void *args) with gil:
1984 Callback to onsafe() for asynchronous operations
1986 cdef object cb = <object>args
1991 cdef int __aio_complete_cb(rados_completion_t completion, void *args) with gil:
1993 Callback to oncomplete() for asynchronous operations
1995 cdef object cb = <object>args
2000 cdef class Ioctx(object):
2001 """rados.Ioctx object"""
2002 # NOTE(sileht): attributes declared in .pyd
2004 def __init__(self, name):
2008 self.locator_key = ""
2010 self.lock = threading.Lock()
2011 self.safe_completions = []
2012 self.complete_completions = []
2014 def __enter__(self):
2017 def __exit__(self, type_, value, traceback):
2021 def __dealloc__(self):
2024 def __track_completion(self, completion_obj):
2025 if completion_obj.oncomplete:
2027 self.complete_completions.append(completion_obj)
2028 if completion_obj.onsafe:
2030 self.safe_completions.append(completion_obj)
2032 def __get_completion(self, oncomplete, onsafe):
2034 Constructs a completion to use with asynchronous operations
2036 :param oncomplete: what to do when the write is safe and complete in memory
2038 :type oncomplete: completion
2039 :param onsafe: what to do when the write is safe and complete on storage
2041 :type onsafe: completion
2043 :raises: :class:`Error`
2044 :returns: completion object
2047 completion_obj = Completion(self, oncomplete, onsafe)
2050 rados_callback_t complete_cb = NULL
2051 rados_callback_t safe_cb = NULL
2052 rados_completion_t completion
2053 PyObject* p_completion_obj= <PyObject*>completion_obj
2056 complete_cb = <rados_callback_t>&__aio_complete_cb
2058 safe_cb = <rados_callback_t>&__aio_safe_cb
2061 ret = rados_aio_create_completion(p_completion_obj, complete_cb, safe_cb,
2064 raise make_ex(ret, "error getting a completion")
2066 completion_obj.rados_comp = completion
2067 return completion_obj
2069 @requires(('object_name', str_type), ('oncomplete', opt(Callable)))
2070 def aio_stat(self, object_name, oncomplete):
2072 Asynchronously get object stats (size/mtime)
2074 oncomplete will be called with the returned size and mtime
2075 as well as the completion:
2077 oncomplete(completion, size, mtime)
2079 :param object_name: the name of the object to get stats from
2080 :type object_name: str
2081 :param oncomplete: what to do when the stat is complete
2082 :type oncomplete: completion
2084 :raises: :class:`Error`
2085 :returns: completion object
2088 object_name = cstr(object_name, 'object_name')
2091 Completion completion
2092 char *_object_name = object_name
2096 def oncomplete_(completion_v):
2097 cdef Completion _completion_v = completion_v
2098 return_value = _completion_v.get_return_value()
2099 if return_value >= 0:
2100 return oncomplete(_completion_v, psize, time.localtime(pmtime))
2102 return oncomplete(_completion_v, None, None)
2104 completion = self.__get_completion(oncomplete_, None)
2105 self.__track_completion(completion)
2107 ret = rados_aio_stat(self.io, _object_name, completion.rados_comp,
2111 completion._cleanup()
2112 raise make_ex(ret, "error stating %s" % object_name)
2115 @requires(('object_name', str_type), ('to_write', bytes), ('offset', int),
2116 ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2117 def aio_write(self, object_name, to_write, offset=0,
2118 oncomplete=None, onsafe=None):
2120 Write data to an object asynchronously
2122 Queues the write and returns.
2124 :param object_name: name of the object
2125 :type object_name: str
2126 :param to_write: data to write
2127 :type to_write: bytes
2128 :param offset: byte offset in the object to begin writing at
2130 :param oncomplete: what to do when the write is safe and complete in memory
2132 :type oncomplete: completion
2133 :param onsafe: what to do when the write is safe and complete on storage
2135 :type onsafe: completion
2137 :raises: :class:`Error`
2138 :returns: completion object
2141 object_name = cstr(object_name, 'object_name')
2144 Completion completion
2145 char* _object_name = object_name
2146 char* _to_write = to_write
2147 size_t size = len(to_write)
2148 uint64_t _offset = offset
2150 completion = self.__get_completion(oncomplete, onsafe)
2151 self.__track_completion(completion)
2153 ret = rados_aio_write(self.io, _object_name, completion.rados_comp,
2154 _to_write, size, _offset)
2156 completion._cleanup()
2157 raise make_ex(ret, "error writing object %s" % object_name)
2160 @requires(('object_name', str_type), ('to_write', bytes), ('oncomplete', opt(Callable)),
2161 ('onsafe', opt(Callable)))
2162 def aio_write_full(self, object_name, to_write,
2163 oncomplete=None, onsafe=None):
2165 Asychronously write an entire object
2167 The object is filled with the provided data. If the object exists,
2168 it is atomically truncated and then written.
2169 Queues the write and returns.
2171 :param object_name: name of the object
2172 :type object_name: str
2173 :param to_write: data to write
2175 :param oncomplete: what to do when the write is safe and complete in memory
2177 :type oncomplete: completion
2178 :param onsafe: what to do when the write is safe and complete on storage
2180 :type onsafe: completion
2182 :raises: :class:`Error`
2183 :returns: completion object
2186 object_name = cstr(object_name, 'object_name')
2189 Completion completion
2190 char* _object_name = object_name
2191 char* _to_write = to_write
2192 size_t size = len(to_write)
2194 completion = self.__get_completion(oncomplete, onsafe)
2195 self.__track_completion(completion)
2197 ret = rados_aio_write_full(self.io, _object_name,
2198 completion.rados_comp,
2201 completion._cleanup()
2202 raise make_ex(ret, "error writing object %s" % object_name)
2205 @requires(('object_name', str_type), ('to_append', bytes), ('oncomplete', opt(Callable)),
2206 ('onsafe', opt(Callable)))
2207 def aio_append(self, object_name, to_append, oncomplete=None, onsafe=None):
2209 Asychronously append data to an object
2211 Queues the write and returns.
2213 :param object_name: name of the object
2214 :type object_name: str
2215 :param to_append: data to append
2216 :type to_append: str
2217 :param offset: byte offset in the object to begin writing at
2219 :param oncomplete: what to do when the write is safe and complete in memory
2221 :type oncomplete: completion
2222 :param onsafe: what to do when the write is safe and complete on storage
2224 :type onsafe: completion
2226 :raises: :class:`Error`
2227 :returns: completion object
2229 object_name = cstr(object_name, 'object_name')
2232 Completion completion
2233 char* _object_name = object_name
2234 char* _to_append = to_append
2235 size_t size = len(to_append)
2237 completion = self.__get_completion(oncomplete, onsafe)
2238 self.__track_completion(completion)
2240 ret = rados_aio_append(self.io, _object_name,
2241 completion.rados_comp,
2244 completion._cleanup()
2245 raise make_ex(ret, "error appending object %s" % object_name)
2248 def aio_flush(self):
2250 Block until all pending writes in an io context are safe
2252 :raises: :class:`Error`
2255 ret = rados_aio_flush(self.io)
2257 raise make_ex(ret, "error flushing")
2259 @requires(('object_name', str_type), ('length', int), ('offset', int),
2260 ('oncomplete', opt(Callable)))
2261 def aio_read(self, object_name, length, offset, oncomplete):
2263 Asychronously read data from an object
2265 oncomplete will be called with the returned read value as
2266 well as the completion:
2268 oncomplete(completion, data_read)
2270 :param object_name: name of the object to read from
2271 :type object_name: str
2272 :param length: the number of bytes to read
2274 :param offset: byte offset in the object to begin reading from
2276 :param oncomplete: what to do when the read is complete
2277 :type oncomplete: completion
2279 :raises: :class:`Error`
2280 :returns: completion object
2283 object_name = cstr(object_name, 'object_name')
2286 Completion completion
2287 char* _object_name = object_name
2288 uint64_t _offset = offset
2291 size_t _length = length
2293 def oncomplete_(completion_v):
2294 cdef Completion _completion_v = completion_v
2295 return_value = _completion_v.get_return_value()
2296 if return_value > 0 and return_value != length:
2297 _PyBytes_Resize(&_completion_v.buf, return_value)
2298 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2300 completion = self.__get_completion(oncomplete_, None)
2301 completion.buf = PyBytes_FromStringAndSize(NULL, length)
2302 ret_buf = PyBytes_AsString(completion.buf)
2303 self.__track_completion(completion)
2305 ret = rados_aio_read(self.io, _object_name, completion.rados_comp,
2306 ret_buf, _length, _offset)
2308 completion._cleanup()
2309 raise make_ex(ret, "error reading %s" % object_name)
2312 @requires(('object_name', str_type), ('cls', str_type), ('method', str_type),
2313 ('data', bytes), ('length', int),
2314 ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2315 def aio_execute(self, object_name, cls, method, data,
2316 length=8192, oncomplete=None, onsafe=None):
2318 Asynchronously execute an OSD class method on an object.
2320 oncomplete and onsafe will be called with the data returned from
2321 the plugin as well as the completion:
2323 oncomplete(completion, data)
2324 onsafe(completion, data)
2326 :param object_name: name of the object
2327 :type object_name: str
2328 :param cls: name of the object class
2330 :param method: name of the method
2332 :param data: input data
2334 :param length: size of output buffer in bytes (default=8192)
2336 :param oncomplete: what to do when the execution is complete
2337 :type oncomplete: completion
2338 :param onsafe: what to do when the execution is safe and complete
2339 :type onsafe: completion
2341 :raises: :class:`Error`
2342 :returns: completion object
2345 object_name = cstr(object_name, 'object_name')
2346 cls = cstr(cls, 'cls')
2347 method = cstr(method, 'method')
2349 Completion completion
2350 char *_object_name = object_name
2352 char *_method = method
2354 size_t _data_len = len(data)
2357 size_t _length = length
2359 def oncomplete_(completion_v):
2360 cdef Completion _completion_v = completion_v
2361 return_value = _completion_v.get_return_value()
2362 if return_value > 0 and return_value != length:
2363 _PyBytes_Resize(&_completion_v.buf, return_value)
2364 return oncomplete(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2366 def onsafe_(completion_v):
2367 cdef Completion _completion_v = completion_v
2368 return_value = _completion_v.get_return_value()
2369 return onsafe(_completion_v, <object>_completion_v.buf if return_value >= 0 else None)
2371 completion = self.__get_completion(oncomplete_ if oncomplete else None, onsafe_ if onsafe else None)
2372 completion.buf = PyBytes_FromStringAndSize(NULL, length)
2373 ret_buf = PyBytes_AsString(completion.buf)
2374 self.__track_completion(completion)
2376 ret = rados_aio_exec(self.io, _object_name, completion.rados_comp,
2377 _cls, _method, _data, _data_len, ret_buf, _length)
2379 completion._cleanup()
2380 raise make_ex(ret, "error executing %s::%s on %s" % (cls, method, object_name))
2383 @requires(('object_name', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)))
2384 def aio_remove(self, object_name, oncomplete=None, onsafe=None):
2386 Asychronously remove an object
2388 :param object_name: name of the object to remove
2389 :type object_name: str
2390 :param oncomplete: what to do when the remove is safe and complete in memory
2392 :type oncomplete: completion
2393 :param onsafe: what to do when the remove is safe and complete on storage
2395 :type onsafe: completion
2397 :raises: :class:`Error`
2398 :returns: completion object
2400 object_name = cstr(object_name, 'object_name')
2403 Completion completion
2404 char* _object_name = object_name
2406 completion = self.__get_completion(oncomplete, onsafe)
2407 self.__track_completion(completion)
2409 ret = rados_aio_remove(self.io, _object_name,
2410 completion.rados_comp)
2412 completion._cleanup()
2413 raise make_ex(ret, "error removing %s" % object_name)
2416 def require_ioctx_open(self):
2418 Checks if the rados.Ioctx object state is 'open'
2420 :raises: IoctxStateError
2422 if self.state != "open":
2423 raise IoctxStateError("The pool is %s" % self.state)
2425 def change_auid(self, auid):
2427 Attempt to change an io context's associated auid "owner."
2429 Requires that you have write permission on both the current and new
2432 :raises: :class:`Error`
2434 self.require_ioctx_open()
2437 uint64_t _auid = auid
2440 ret = rados_ioctx_pool_set_auid(self.io, _auid)
2442 raise make_ex(ret, "error changing auid of '%s' to %d"
2443 % (self.name, auid))
2445 @requires(('loc_key', str_type))
2446 def set_locator_key(self, loc_key):
2448 Set the key for mapping objects to pgs within an io context.
2450 The key is used instead of the object name to determine which
2451 placement groups an object is put in. This affects all subsequent
2452 operations of the io context - until a different locator key is
2453 set, all objects in this io context will be placed in the same pg.
2455 :param loc_key: the key to use as the object locator, or NULL to discard
2456 any previously set key
2459 :raises: :class:`TypeError`
2461 self.require_ioctx_open()
2462 cloc_key = cstr(loc_key, 'loc_key')
2463 cdef char *_loc_key = cloc_key
2465 rados_ioctx_locator_set_key(self.io, _loc_key)
2466 self.locator_key = loc_key
2468 def get_locator_key(self):
2470 Get the locator_key of context
2472 :returns: locator_key
2474 return self.locator_key
2476 @requires(('snap_id', long))
2477 def set_read(self, snap_id):
2479 Set the snapshot for reading objects.
2481 To stop to read from snapshot, use set_read(LIBRADOS_SNAP_HEAD)
2483 :param snap_id: the snapshot Id
2486 :raises: :class:`TypeError`
2488 self.require_ioctx_open()
2489 cdef rados_snap_t _snap_id = snap_id
2491 rados_ioctx_snap_set_read(self.io, _snap_id)
2493 @requires(('nspace', str_type))
2494 def set_namespace(self, nspace):
2496 Set the namespace for objects within an io context.
2498 The namespace in addition to the object name fully identifies
2499 an object. This affects all subsequent operations of the io context
2500 - until a different namespace is set, all objects in this io context
2501 will be placed in the same namespace.
2503 :param nspace: the namespace to use, or None/"" for the default namespace
2506 :raises: :class:`TypeError`
2508 self.require_ioctx_open()
2511 cnspace = cstr(nspace, 'nspace')
2512 cdef char *_nspace = cnspace
2514 rados_ioctx_set_namespace(self.io, _nspace)
2515 self.nspace = nspace
2517 def get_namespace(self):
2519 Get the namespace of context
2527 Close a rados.Ioctx object.
2529 This just tells librados that you no longer need to use the io context.
2530 It may not be freed immediately if there are pending asynchronous
2531 requests on it, but you should not use an io context again after
2532 calling this function on it.
2534 if self.state == "open":
2535 self.require_ioctx_open()
2537 rados_ioctx_destroy(self.io)
2538 self.state = "closed"
2541 @requires(('key', str_type), ('data', bytes))
2542 def write(self, key, data, offset=0):
2544 Write data to an object synchronously
2546 :param key: name of the object
2548 :param data: data to write
2550 :param offset: byte offset in the object to begin writing at
2553 :raises: :class:`TypeError`
2554 :raises: :class:`LogicError`
2555 :returns: int - 0 on success
2557 self.require_ioctx_open()
2559 key = cstr(key, 'key')
2563 size_t length = len(data)
2564 uint64_t _offset = offset
2567 ret = rados_write(self.io, _key, _data, length, _offset)
2571 raise make_ex(ret, "Ioctx.write(%s): failed to write %s"
2574 raise LogicError("Ioctx.write(%s): rados_write \
2575 returned %d, but should return zero on success." % (self.name, ret))
2577 @requires(('key', str_type), ('data', bytes))
2578 def write_full(self, key, data):
2580 Write an entire object synchronously.
2582 The object is filled with the provided data. If the object exists,
2583 it is atomically truncated and then written.
2585 :param key: name of the object
2587 :param data: data to write
2590 :raises: :class:`TypeError`
2591 :raises: :class:`Error`
2592 :returns: int - 0 on success
2594 self.require_ioctx_open()
2595 key = cstr(key, 'key')
2599 size_t length = len(data)
2602 ret = rados_write_full(self.io, _key, _data, length)
2606 raise make_ex(ret, "Ioctx.write_full(%s): failed to write %s"
2609 raise LogicError("Ioctx.write_full(%s): rados_write_full \
2610 returned %d, but should return zero on success." % (self.name, ret))
2612 @requires(('key', str_type), ('data', bytes))
2613 def append(self, key, data):
2615 Append data to an object synchronously
2617 :param key: name of the object
2619 :param data: data to write
2622 :raises: :class:`TypeError`
2623 :raises: :class:`LogicError`
2624 :returns: int - 0 on success
2626 self.require_ioctx_open()
2627 key = cstr(key, 'key')
2631 size_t length = len(data)
2634 ret = rados_append(self.io, _key, _data, length)
2638 raise make_ex(ret, "Ioctx.append(%s): failed to append %s"
2641 raise LogicError("Ioctx.append(%s): rados_append \
2642 returned %d, but should return zero on success." % (self.name, ret))
2644 @requires(('key', str_type))
2645 def read(self, key, length=8192, offset=0):
2647 Read data from an object synchronously
2649 :param key: name of the object
2651 :param length: the number of bytes to read (default=8192)
2653 :param offset: byte offset in the object to begin reading at
2656 :raises: :class:`TypeError`
2657 :raises: :class:`Error`
2658 :returns: str - data read from object
2660 self.require_ioctx_open()
2661 key = cstr(key, 'key')
2665 uint64_t _offset = offset
2666 size_t _length = length
2667 PyObject* ret_s = NULL
2669 ret_s = PyBytes_FromStringAndSize(NULL, length)
2671 ret_buf = PyBytes_AsString(ret_s)
2673 ret = rados_read(self.io, _key, ret_buf, _length, _offset)
2675 raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key))
2678 _PyBytes_Resize(&ret_s, ret)
2680 return <object>ret_s
2682 # We DECREF unconditionally: the cast to object above will have
2683 # INCREFed if necessary. This also takes care of exceptions,
2684 # including if _PyString_Resize fails (that will free the string
2685 # itself and set ret_s to NULL, hence XDECREF).
2686 ref.Py_XDECREF(ret_s)
2688 @requires(('key', str_type), ('cls', str_type), ('method', str_type), ('data', bytes))
2689 def execute(self, key, cls, method, data, length=8192):
2691 Execute an OSD class method on an object.
2693 :param key: name of the object
2695 :param cls: name of the object class
2697 :param method: name of the method
2699 :param data: input data
2701 :param length: size of output buffer in bytes (default=8192)
2704 :raises: :class:`TypeError`
2705 :raises: :class:`Error`
2706 :returns: (ret, method output)
2708 self.require_ioctx_open()
2710 key = cstr(key, 'key')
2711 cls = cstr(cls, 'cls')
2712 method = cstr(method, 'method')
2716 char *_method = method
2718 size_t _data_len = len(data)
2721 size_t _length = length
2722 PyObject* ret_s = NULL
2724 ret_s = PyBytes_FromStringAndSize(NULL, length)
2726 ret_buf = PyBytes_AsString(ret_s)
2728 ret = rados_exec(self.io, _key, _cls, _method, _data,
2729 _data_len, ret_buf, _length)
2731 raise make_ex(ret, "Ioctx.read(%s): failed to read %s" % (self.name, key))
2734 _PyBytes_Resize(&ret_s, ret)
2736 return ret, <object>ret_s
2738 # We DECREF unconditionally: the cast to object above will have
2739 # INCREFed if necessary. This also takes care of exceptions,
2740 # including if _PyString_Resize fails (that will free the string
2741 # itself and set ret_s to NULL, hence XDECREF).
2742 ref.Py_XDECREF(ret_s)
2744 def get_stats(self):
2746 Get pool usage statistics
2748 :returns: dict - contains the following keys:
2750 - ``num_bytes`` (int) - size of pool in bytes
2752 - ``num_kb`` (int) - size of pool in kbytes
2754 - ``num_objects`` (int) - number of objects in the pool
2756 - ``num_object_clones`` (int) - number of object clones
2758 - ``num_object_copies`` (int) - number of object copies
2760 - ``num_objects_missing_on_primary`` (int) - number of objets
2763 - ``num_objects_unfound`` (int) - number of unfound objects
2765 - ``num_objects_degraded`` (int) - number of degraded objects
2767 - ``num_rd`` (int) - bytes read
2769 - ``num_rd_kb`` (int) - kbytes read
2771 - ``num_wr`` (int) - bytes written
2773 - ``num_wr_kb`` (int) - kbytes written
2775 self.require_ioctx_open()
2776 cdef rados_pool_stat_t stats
2778 ret = rados_ioctx_pool_stat(self.io, &stats)
2780 raise make_ex(ret, "Ioctx.get_stats(%s): get_stats failed" % self.name)
2781 return {'num_bytes': stats.num_bytes,
2782 'num_kb': stats.num_kb,
2783 'num_objects': stats.num_objects,
2784 'num_object_clones': stats.num_object_clones,
2785 'num_object_copies': stats.num_object_copies,
2786 "num_objects_missing_on_primary": stats.num_objects_missing_on_primary,
2787 "num_objects_unfound": stats.num_objects_unfound,
2788 "num_objects_degraded": stats.num_objects_degraded,
2789 "num_rd": stats.num_rd,
2790 "num_rd_kb": stats.num_rd_kb,
2791 "num_wr": stats.num_wr,
2792 "num_wr_kb": stats.num_wr_kb}
2794 @requires(('key', str_type))
2795 def remove_object(self, key):
2799 This does not delete any snapshots of the object.
2801 :param key: the name of the object to delete
2804 :raises: :class:`TypeError`
2805 :raises: :class:`Error`
2806 :returns: bool - True on success
2808 self.require_ioctx_open()
2809 key = cstr(key, 'key')
2814 ret = rados_remove(self.io, _key)
2816 raise make_ex(ret, "Failed to remove '%s'" % key)
2819 @requires(('key', str_type))
2820 def trunc(self, key, size):
2824 If this enlarges the object, the new area is logically filled with
2825 zeroes. If this shrinks the object, the excess data is removed.
2827 :param key: the name of the object to resize
2829 :param size: the new size of the object in bytes
2832 :raises: :class:`TypeError`
2833 :raises: :class:`Error`
2834 :returns: int - 0 on success, otherwise raises error
2837 self.require_ioctx_open()
2838 key = cstr(key, 'key')
2841 uint64_t _size = size
2844 ret = rados_trunc(self.io, _key, _size)
2846 raise make_ex(ret, "Ioctx.trunc(%s): failed to truncate %s" % (self.name, key))
2849 @requires(('key', str_type))
2850 def stat(self, key):
2852 Get object stats (size/mtime)
2854 :param key: the name of the object to get stats from
2857 :raises: :class:`TypeError`
2858 :raises: :class:`Error`
2859 :returns: (size,timestamp)
2861 self.require_ioctx_open()
2863 key = cstr(key, 'key')
2870 ret = rados_stat(self.io, _key, &psize, &pmtime)
2872 raise make_ex(ret, "Failed to stat %r" % key)
2873 return psize, time.localtime(pmtime)
2875 @requires(('key', str_type), ('xattr_name', str_type))
2876 def get_xattr(self, key, xattr_name):
2878 Get the value of an extended attribute on an object.
2880 :param key: the name of the object to get xattr from
2882 :param xattr_name: which extended attribute to read
2883 :type xattr_name: str
2885 :raises: :class:`TypeError`
2886 :raises: :class:`Error`
2887 :returns: str - value of the xattr
2889 self.require_ioctx_open()
2891 key = cstr(key, 'key')
2892 xattr_name = cstr(xattr_name, 'xattr_name')
2895 char *_xattr_name = xattr_name
2896 size_t ret_length = 4096
2897 char *ret_buf = NULL
2900 while ret_length < 4096 * 1024 * 1024:
2901 ret_buf = <char *>realloc_chk(ret_buf, ret_length)
2903 ret = rados_getxattr(self.io, _key, _xattr_name, ret_buf, ret_length)
2904 if ret == -errno.ERANGE:
2907 raise make_ex(ret, "Failed to get xattr %r" % xattr_name)
2910 return ret_buf[:ret]
2914 @requires(('oid', str_type))
2915 def get_xattrs(self, oid):
2917 Start iterating over xattrs on an object.
2919 :param oid: the name of the object to get xattrs from
2922 :raises: :class:`TypeError`
2923 :raises: :class:`Error`
2924 :returns: XattrIterator
2926 self.require_ioctx_open()
2927 return XattrIterator(self, oid)
2929 @requires(('key', str_type), ('xattr_name', str_type), ('xattr_value', bytes))
2930 def set_xattr(self, key, xattr_name, xattr_value):
2932 Set an extended attribute on an object.
2934 :param key: the name of the object to set xattr to
2936 :param xattr_name: which extended attribute to set
2937 :type xattr_name: str
2938 :param xattr_value: the value of the extended attribute
2939 :type xattr_value: bytes
2941 :raises: :class:`TypeError`
2942 :raises: :class:`Error`
2943 :returns: bool - True on success, otherwise raise an error
2945 self.require_ioctx_open()
2947 key = cstr(key, 'key')
2948 xattr_name = cstr(xattr_name, 'xattr_name')
2951 char *_xattr_name = xattr_name
2952 char *_xattr_value = xattr_value
2953 size_t _xattr_value_len = len(xattr_value)
2956 ret = rados_setxattr(self.io, _key, _xattr_name,
2957 _xattr_value, _xattr_value_len)
2959 raise make_ex(ret, "Failed to set xattr %r" % xattr_name)
2962 @requires(('key', str_type), ('xattr_name', str_type))
2963 def rm_xattr(self, key, xattr_name):
2965 Removes an extended attribute on from an object.
2967 :param key: the name of the object to remove xattr from
2969 :param xattr_name: which extended attribute to remove
2970 :type xattr_name: str
2972 :raises: :class:`TypeError`
2973 :raises: :class:`Error`
2974 :returns: bool - True on success, otherwise raise an error
2976 self.require_ioctx_open()
2978 key = cstr(key, 'key')
2979 xattr_name = cstr(xattr_name, 'xattr_name')
2982 char *_xattr_name = xattr_name
2985 ret = rados_rmxattr(self.io, _key, _xattr_name)
2987 raise make_ex(ret, "Failed to delete key %r xattr %r" %
2991 def list_objects(self):
2993 Get ObjectIterator on rados.Ioctx object.
2995 :returns: ObjectIterator
2997 self.require_ioctx_open()
2998 return ObjectIterator(self)
3000 def list_snaps(self):
3002 Get SnapIterator on rados.Ioctx object.
3004 :returns: SnapIterator
3006 self.require_ioctx_open()
3007 return SnapIterator(self)
3009 @requires(('snap_name', str_type))
3010 def create_snap(self, snap_name):
3012 Create a pool-wide snapshot
3014 :param snap_name: the name of the snapshot
3015 :type snap_name: str
3017 :raises: :class:`TypeError`
3018 :raises: :class:`Error`
3020 self.require_ioctx_open()
3021 snap_name = cstr(snap_name, 'snap_name')
3022 cdef char *_snap_name = snap_name
3025 ret = rados_ioctx_snap_create(self.io, _snap_name)
3027 raise make_ex(ret, "Failed to create snap %s" % snap_name)
3029 @requires(('snap_name', str_type))
3030 def remove_snap(self, snap_name):
3032 Removes a pool-wide snapshot
3034 :param snap_name: the name of the snapshot
3035 :type snap_name: str
3037 :raises: :class:`TypeError`
3038 :raises: :class:`Error`
3040 self.require_ioctx_open()
3041 snap_name = cstr(snap_name, 'snap_name')
3042 cdef char *_snap_name = snap_name
3045 ret = rados_ioctx_snap_remove(self.io, _snap_name)
3047 raise make_ex(ret, "Failed to remove snap %s" % snap_name)
3049 @requires(('snap_name', str_type))
3050 def lookup_snap(self, snap_name):
3052 Get the id of a pool snapshot
3054 :param snap_name: the name of the snapshot to lookop
3055 :type snap_name: str
3057 :raises: :class:`TypeError`
3058 :raises: :class:`Error`
3059 :returns: Snap - on success
3061 self.require_ioctx_open()
3062 csnap_name = cstr(snap_name, 'snap_name')
3064 char *_snap_name = csnap_name
3065 rados_snap_t snap_id
3068 ret = rados_ioctx_snap_lookup(self.io, _snap_name, &snap_id)
3070 raise make_ex(ret, "Failed to lookup snap %s" % snap_name)
3071 return Snap(self, snap_name, int(snap_id))
3073 @requires(('oid', str_type), ('snap_name', str_type))
3074 def snap_rollback(self, oid, snap_name):
3076 Rollback an object to a snapshot
3078 :param oid: the name of the object
3080 :param snap_name: the name of the snapshot
3081 :type snap_name: str
3083 :raises: :class:`TypeError`
3084 :raises: :class:`Error`
3086 self.require_ioctx_open()
3087 oid = cstr(oid, 'oid')
3088 snap_name = cstr(snap_name, 'snap_name')
3090 char *_snap_name = snap_name
3094 ret = rados_ioctx_snap_rollback(self.io, _oid, _snap_name)
3096 raise make_ex(ret, "Failed to rollback %s" % oid)
3098 def get_last_version(self):
3100 Return the version of the last object read or written to.
3102 This exposes the internal version number of the last object read or
3103 written via this io context
3105 :returns: version of the last object used
3107 self.require_ioctx_open()
3109 ret = rados_get_last_version(self.io)
3112 def create_write_op(self):
3114 create write operation object.
3115 need call release_write_op after use
3117 return WriteOp().create()
3119 def create_read_op(self):
3121 create read operation object.
3122 need call release_read_op after use
3124 return ReadOp().create()
3126 def release_write_op(self, write_op):
3128 release memory alloc by create_write_op
3132 def release_read_op(self, read_op):
3134 release memory alloc by create_read_op
3135 :para read_op: read_op object
3140 @requires(('write_op', WriteOp), ('keys', tuple), ('values', tuple))
3141 def set_omap(self, write_op, keys, values):
3143 set keys values to write_op
3144 :para write_op: write_operation object
3145 :type write_op: WriteOp
3146 :para keys: a tuple of keys
3148 :para values: a tuple of values
3152 if len(keys) != len(values):
3153 raise Error("Rados(): keys and values must have the same number of items")
3155 keys = cstr_list(keys, 'keys')
3157 WriteOp _write_op = write_op
3158 size_t key_num = len(keys)
3159 char **_keys = to_bytes_array(keys)
3160 char **_values = to_bytes_array(values)
3161 size_t *_lens = to_csize_t_array([len(v) for v in values])
3165 rados_write_op_omap_set(_write_op.write_op,
3166 <const char**>_keys,
3167 <const char**>_values,
3168 <const size_t*>_lens, key_num)
3174 @requires(('write_op', WriteOp), ('oid', str_type), ('mtime', opt(int)), ('flags', opt(int)))
3175 def operate_write_op(self, write_op, oid, mtime=0, flags=LIBRADOS_OPERATION_NOFLAG):
3177 excute the real write operation
3178 :para write_op: write operation object
3179 :type write_op: WriteOp
3180 :para oid: object name
3182 :para mtime: the time to set the mtime to, 0 for the current time
3184 :para flags: flags to apply to the entire operation
3188 oid = cstr(oid, 'oid')
3190 WriteOp _write_op = write_op
3192 time_t _mtime = mtime
3196 ret = rados_write_op_operate(_write_op.write_op, self.io, _oid, &_mtime, _flags)
3198 raise make_ex(ret, "Failed to operate write op for oid %s" % oid)
3200 @requires(('write_op', WriteOp), ('oid', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)), ('mtime', opt(int)), ('flags', opt(int)))
3201 def operate_aio_write_op(self, write_op, oid, oncomplete=None, onsafe=None, mtime=0, flags=LIBRADOS_OPERATION_NOFLAG):
3203 excute the real write operation asynchronously
3204 :para write_op: write operation object
3205 :type write_op: WriteOp
3206 :para oid: object name
3208 :param oncomplete: what to do when the remove is safe and complete in memory
3210 :type oncomplete: completion
3211 :param onsafe: what to do when the remove is safe and complete on storage
3213 :type onsafe: completion
3214 :para mtime: the time to set the mtime to, 0 for the current time
3216 :para flags: flags to apply to the entire operation
3219 :raises: :class:`Error`
3220 :returns: completion object
3223 oid = cstr(oid, 'oid')
3225 WriteOp _write_op = write_op
3227 Completion completion
3228 time_t _mtime = mtime
3231 completion = self.__get_completion(oncomplete, onsafe)
3232 self.__track_completion(completion)
3235 ret = rados_aio_write_op_operate(_write_op.write_op, self.io, completion.rados_comp, _oid,
3238 completion._cleanup()
3239 raise make_ex(ret, "Failed to operate aio write op for oid %s" % oid)
3242 @requires(('read_op', ReadOp), ('oid', str_type), ('flag', opt(int)))
3243 def operate_read_op(self, read_op, oid, flag=LIBRADOS_OPERATION_NOFLAG):
3245 excute the real read operation
3246 :para read_op: read operation object
3247 :type read_op: ReadOp
3248 :para oid: object name
3250 :para flag: flags to apply to the entire operation
3253 oid = cstr(oid, 'oid')
3255 ReadOp _read_op = read_op
3260 ret = rados_read_op_operate(_read_op.read_op, self.io, _oid, _flag)
3262 raise make_ex(ret, "Failed to operate read op for oid %s" % oid)
3264 @requires(('read_op', ReadOp), ('oid', str_type), ('oncomplete', opt(Callable)), ('onsafe', opt(Callable)), ('flag', opt(int)))
3265 def operate_aio_read_op(self, read_op, oid, oncomplete=None, onsafe=None, flag=LIBRADOS_OPERATION_NOFLAG):
3267 excute the real read operation
3268 :para read_op: read operation object
3269 :type read_op: ReadOp
3270 :para oid: object name
3272 :param oncomplete: what to do when the remove is safe and complete in memory
3274 :type oncomplete: completion
3275 :param onsafe: what to do when the remove is safe and complete on storage
3277 :type onsafe: completion
3278 :para flag: flags to apply to the entire operation
3281 oid = cstr(oid, 'oid')
3283 ReadOp _read_op = read_op
3285 Completion completion
3288 completion = self.__get_completion(oncomplete, onsafe)
3289 self.__track_completion(completion)
3292 ret = rados_aio_read_op_operate(_read_op.read_op, self.io, completion.rados_comp, _oid, _flag)
3294 completion._cleanup()
3295 raise make_ex(ret, "Failed to operate aio read op for oid %s" % oid)
3298 @requires(('read_op', ReadOp), ('start_after', str_type), ('filter_prefix', str_type), ('max_return', int))
3299 def get_omap_vals(self, read_op, start_after, filter_prefix, max_return):
3302 :para read_op: read operation object
3303 :type read_op: ReadOp
3304 :para start_after: list keys starting after start_after
3305 :type start_after: str
3306 :para filter_prefix: list only keys beginning with filter_prefix
3307 :type filter_prefix: str
3308 :para max_return: list no more than max_return key/value pairs
3309 :type max_return: int
3310 :returns: an iterator over the requested omap values, return value from this action
3313 start_after = cstr(start_after, 'start_after') if start_after else None
3314 filter_prefix = cstr(filter_prefix, 'filter_prefix') if filter_prefix else None
3316 char *_start_after = opt_str(start_after)
3317 char *_filter_prefix = opt_str(filter_prefix)
3318 ReadOp _read_op = read_op
3319 rados_omap_iter_t iter_addr = NULL
3320 int _max_return = max_return
3324 rados_read_op_omap_get_vals(_read_op.read_op, _start_after, _filter_prefix,
3325 _max_return, &iter_addr, &prval)
3326 it = OmapIterator(self)
3328 return it, int(prval)
3330 @requires(('read_op', ReadOp), ('start_after', str_type), ('max_return', int))
3331 def get_omap_keys(self, read_op, start_after, max_return):
3334 :para read_op: read operation object
3335 :type read_op: ReadOp
3336 :para start_after: list keys starting after start_after
3337 :type start_after: str
3338 :para max_return: list no more than max_return key/value pairs
3339 :type max_return: int
3340 :returns: an iterator over the requested omap values, return value from this action
3342 start_after = cstr(start_after, 'start_after') if start_after else None
3344 char *_start_after = opt_str(start_after)
3345 ReadOp _read_op = read_op
3346 rados_omap_iter_t iter_addr = NULL
3347 int _max_return = max_return
3351 rados_read_op_omap_get_keys(_read_op.read_op, _start_after,
3352 _max_return, &iter_addr, &prval)
3353 it = OmapIterator(self)
3355 return it, int(prval)
3357 @requires(('read_op', ReadOp), ('keys', tuple))
3358 def get_omap_vals_by_keys(self, read_op, keys):
3360 get the omap values by keys
3361 :para read_op: read operation object
3362 :type read_op: ReadOp
3363 :para keys: input key tuple
3365 :returns: an iterator over the requested omap values, return value from this action
3367 keys = cstr_list(keys, 'keys')
3369 ReadOp _read_op = read_op
3370 rados_omap_iter_t iter_addr
3371 char **_keys = to_bytes_array(keys)
3372 size_t key_num = len(keys)
3377 rados_read_op_omap_get_vals_by_keys(_read_op.read_op,
3378 <const char**>_keys,
3379 key_num, &iter_addr, &prval)
3380 it = OmapIterator(self)
3382 return it, int(prval)
3386 @requires(('write_op', WriteOp), ('keys', tuple))
3387 def remove_omap_keys(self, write_op, keys):
3389 remove omap keys specifiled
3390 :para write_op: write operation object
3391 :type write_op: WriteOp
3392 :para keys: input key tuple
3396 keys = cstr_list(keys, 'keys')
3398 WriteOp _write_op = write_op
3399 size_t key_num = len(keys)
3400 char **_keys = to_bytes_array(keys)
3404 rados_write_op_omap_rm_keys(_write_op.write_op, <const char**>_keys, key_num)
3408 @requires(('write_op', WriteOp))
3409 def clear_omap(self, write_op):
3411 Remove all key/value pairs from an object
3412 :para write_op: write operation object
3413 :type write_op: WriteOp
3417 WriteOp _write_op = write_op
3420 rados_write_op_omap_clear(_write_op.write_op)
3422 @requires(('key', str_type), ('name', str_type), ('cookie', str_type), ('desc', str_type),
3423 ('duration', opt(int)), ('flags', int))
3424 def lock_exclusive(self, key, name, cookie, desc="", duration=None, flags=0):
3427 Take an exclusive lock on an object
3429 :param key: name of the object
3431 :param name: name of the lock
3433 :param cookie: cookie of the lock
3435 :param desc: description of the lock
3437 :param duration: duration of the lock in seconds
3442 :raises: :class:`TypeError`
3443 :raises: :class:`Error`
3445 self.require_ioctx_open()
3447 key = cstr(key, 'key')
3448 name = cstr(name, 'name')
3449 cookie = cstr(cookie, 'cookie')
3450 desc = cstr(desc, 'desc')
3455 char* _cookie = cookie
3457 uint8_t _flags = flags
3460 if duration is None:
3462 ret = rados_lock_exclusive(self.io, _key, _name, _cookie, _desc,
3465 _duration.tv_sec = duration
3467 ret = rados_lock_exclusive(self.io, _key, _name, _cookie, _desc,
3471 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
3473 @requires(('key', str_type), ('name', str_type), ('cookie', str_type), ('tag', str_type),
3474 ('desc', str_type), ('duration', opt(int)), ('flags', int))
3475 def lock_shared(self, key, name, cookie, tag, desc="", duration=None, flags=0):
3478 Take a shared lock on an object
3480 :param key: name of the object
3482 :param name: name of the lock
3484 :param cookie: cookie of the lock
3486 :param tag: tag of the lock
3488 :param desc: description of the lock
3490 :param duration: duration of the lock in seconds
3495 :raises: :class:`TypeError`
3496 :raises: :class:`Error`
3498 self.require_ioctx_open()
3500 key = cstr(key, 'key')
3501 tag = cstr(tag, 'tag')
3502 name = cstr(name, 'name')
3503 cookie = cstr(cookie, 'cookie')
3504 desc = cstr(desc, 'desc')
3510 char* _cookie = cookie
3512 uint8_t _flags = flags
3515 if duration is None:
3517 ret = rados_lock_shared(self.io, _key, _name, _cookie, _tag, _desc,
3520 _duration.tv_sec = duration
3522 ret = rados_lock_shared(self.io, _key, _name, _cookie, _tag, _desc,
3525 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
3527 @requires(('key', str_type), ('name', str_type), ('cookie', str_type))
3528 def unlock(self, key, name, cookie):
3531 Release a shared or exclusive lock on an object
3533 :param key: name of the object
3535 :param name: name of the lock
3537 :param cookie: cookie of the lock
3540 :raises: :class:`TypeError`
3541 :raises: :class:`Error`
3543 self.require_ioctx_open()
3545 key = cstr(key, 'key')
3546 name = cstr(name, 'name')
3547 cookie = cstr(cookie, 'cookie')
3552 char* _cookie = cookie
3555 ret = rados_unlock(self.io, _key, _name, _cookie)
3557 raise make_ex(ret, "Ioctx.rados_lock_exclusive(%s): failed to set lock %s on %s" % (self.name, name, key))
3560 def set_object_locator(func):
3561 def retfunc(self, *args, **kwargs):
3562 if self.locator_key is not None:
3563 old_locator = self.ioctx.get_locator_key()
3564 self.ioctx.set_locator_key(self.locator_key)
3565 retval = func(self, *args, **kwargs)
3566 self.ioctx.set_locator_key(old_locator)
3569 return func(self, *args, **kwargs)
3573 def set_object_namespace(func):
3574 def retfunc(self, *args, **kwargs):
3575 if self.nspace is None:
3576 raise LogicError("Namespace not set properly in context")
3577 old_nspace = self.ioctx.get_namespace()
3578 self.ioctx.set_namespace(self.nspace)
3579 retval = func(self, *args, **kwargs)
3580 self.ioctx.set_namespace(old_nspace)
3585 class Object(object):
3586 """Rados object wrapper, makes the object look like a file"""
3587 def __init__(self, ioctx, key, locator_key=None, nspace=None):
3591 self.state = "exists"
3592 self.locator_key = locator_key
3593 self.nspace = "" if nspace is None else nspace
3596 return "rados.Object(ioctx=%s,key=%s,nspace=%s,locator=%s)" % \
3597 (str(self.ioctx), self.key, "--default--"
3598 if self.nspace is "" else self.nspace, self.locator_key)
3600 def require_object_exists(self):
3601 if self.state != "exists":
3602 raise ObjectStateError("The object is %s" % self.state)
3605 @set_object_namespace
3606 def read(self, length=1024 * 1024):
3607 self.require_object_exists()
3608 ret = self.ioctx.read(self.key, length, self.offset)
3609 self.offset += len(ret)
3613 @set_object_namespace
3614 def write(self, string_to_write):
3615 self.require_object_exists()
3616 ret = self.ioctx.write(self.key, string_to_write, self.offset)
3618 self.offset += len(string_to_write)
3622 @set_object_namespace
3624 self.require_object_exists()
3625 self.ioctx.remove_object(self.key)
3626 self.state = "removed"
3629 @set_object_namespace
3631 self.require_object_exists()
3632 return self.ioctx.stat(self.key)
3634 def seek(self, position):
3635 self.require_object_exists()
3636 self.offset = position
3639 @set_object_namespace
3640 def get_xattr(self, xattr_name):
3641 self.require_object_exists()
3642 return self.ioctx.get_xattr(self.key, xattr_name)
3645 @set_object_namespace
3646 def get_xattrs(self):
3647 self.require_object_exists()
3648 return self.ioctx.get_xattrs(self.key)
3651 @set_object_namespace
3652 def set_xattr(self, xattr_name, xattr_value):
3653 self.require_object_exists()
3654 return self.ioctx.set_xattr(self.key, xattr_name, xattr_value)
3657 @set_object_namespace
3658 def rm_xattr(self, xattr_name):
3659 self.require_object_exists()
3660 return self.ioctx.rm_xattr(self.key, xattr_name)
3671 class MonitorLog(object):
3672 # NOTE(sileht): Keep this class for backward compat
3673 # method moved to Rados.monitor_log()
3675 For watching cluster log messages. Instantiate an object and keep
3676 it around while callback is periodically called. Construct with
3677 'level' to monitor 'level' messages (one of MONITOR_LEVELS).
3678 arg will be passed to the callback.
3680 callback will be called with:
3681 arg (given to __init__)
3682 line (the full line, including timestamp, who, level, msg)
3683 who (which entity issued the log message)
3684 timestamp_sec (sec of a struct timespec)
3685 timestamp_nsec (sec of a struct timespec)
3686 seq (sequence number)
3687 level (string representing the level of the log message)
3688 msg (the message itself)
3689 callback's return value is ignored
3691 def __init__(self, cluster, level, callback, arg):
3693 self.callback = callback
3695 self.cluster = cluster
3696 self.cluster.monitor_log(level, callback, arg)