summaryrefslogtreecommitdiffstats
path: root/src/mgr/PyOSDMap.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mgr/PyOSDMap.cc')
-rw-r--r--src/mgr/PyOSDMap.cc682
1 files changed, 682 insertions, 0 deletions
diff --git a/src/mgr/PyOSDMap.cc b/src/mgr/PyOSDMap.cc
new file mode 100644
index 000000000..70813ca52
--- /dev/null
+++ b/src/mgr/PyOSDMap.cc
@@ -0,0 +1,682 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "Mgr.h"
+
+#include "osd/OSDMap.h"
+#include "common/errno.h"
+#include "common/version.h"
+#include "include/stringify.h"
+
+#include "PyOSDMap.h"
+#include "PyFormatter.h"
+#include "Gil.h"
+
+#define dout_context g_ceph_context
+#define dout_subsys ceph_subsys_mgr
+
+
+typedef struct {
+ PyObject_HEAD
+ OSDMap *osdmap;
+} BasePyOSDMap;
+
+typedef struct {
+ PyObject_HEAD
+ OSDMap::Incremental *inc;
+} BasePyOSDMapIncremental;
+
+typedef struct {
+ PyObject_HEAD
+ std::shared_ptr<CrushWrapper> crush;
+} BasePyCRUSH;
+
+// ----------
+
+static PyObject *osdmap_get_epoch(BasePyOSDMap *self, PyObject *obj)
+{
+ return PyLong_FromLong(self->osdmap->get_epoch());
+}
+
+static PyObject *osdmap_get_crush_version(BasePyOSDMap* self, PyObject *obj)
+{
+ return PyLong_FromLong(self->osdmap->get_crush_version());
+}
+
+static PyObject *osdmap_dump(BasePyOSDMap* self, PyObject *obj)
+{
+ PyFormatter f;
+ self->osdmap->dump(&f);
+ return f.get();
+}
+
+static PyObject *osdmap_new_incremental(BasePyOSDMap *self, PyObject *obj)
+{
+ OSDMap::Incremental *inc = new OSDMap::Incremental;
+
+ inc->fsid = self->osdmap->get_fsid();
+ inc->epoch = self->osdmap->get_epoch() + 1;
+ // always include latest crush map here... this is okay since we never
+ // actually use this map in the real world (and even if we did it would
+ // be a no-op).
+ self->osdmap->crush->encode(inc->crush, CEPH_FEATURES_ALL);
+ dout(10) << __func__ << " " << inc << dendl;
+
+ return construct_with_capsule("mgr_module", "OSDMapIncremental",
+ (void*)(inc));
+}
+
+static PyObject *osdmap_apply_incremental(BasePyOSDMap *self,
+ BasePyOSDMapIncremental *incobj)
+{
+ if (!PyObject_TypeCheck(incobj, &BasePyOSDMapIncrementalType)) {
+ derr << "Wrong type in osdmap_apply_incremental!" << dendl;
+ return nullptr;
+ }
+
+ bufferlist bl;
+ self->osdmap->encode(bl, CEPH_FEATURES_ALL|CEPH_FEATURE_RESERVED);
+ OSDMap *next = new OSDMap;
+ next->decode(bl);
+ next->apply_incremental(*(incobj->inc));
+ dout(10) << __func__ << " map " << self->osdmap << " inc " << incobj->inc
+ << " next " << next << dendl;
+
+ return construct_with_capsule("mgr_module", "OSDMap", (void*)next);
+}
+
+static PyObject *osdmap_get_crush(BasePyOSDMap* self, PyObject *obj)
+{
+ return construct_with_capsule("mgr_module", "CRUSHMap",
+ (void*)(&(self->osdmap->crush)));
+}
+
+static PyObject *osdmap_get_pools_by_take(BasePyOSDMap* self, PyObject *args)
+{
+ int take;
+ if (!PyArg_ParseTuple(args, "i:get_pools_by_take",
+ &take)) {
+ return nullptr;
+ }
+
+ PyFormatter f;
+ f.open_array_section("pools");
+ for (auto& p : self->osdmap->get_pools()) {
+ if (self->osdmap->crush->rule_has_take(p.second.crush_rule, take)) {
+ f.dump_int("pool", p.first);
+ }
+ }
+ f.close_section();
+ return f.get();
+}
+
+static PyObject *osdmap_calc_pg_upmaps(BasePyOSDMap* self, PyObject *args)
+{
+ PyObject *pool_list;
+ BasePyOSDMapIncremental *incobj;
+ int max_deviation = 0;
+ int max_iterations = 0;
+ if (!PyArg_ParseTuple(args, "OiiO:calc_pg_upmaps",
+ &incobj, &max_deviation,
+ &max_iterations, &pool_list)) {
+ return nullptr;
+ }
+ if (!PyList_CheckExact(pool_list)) {
+ derr << __func__ << " pool_list not a list" << dendl;
+ return nullptr;
+ }
+ set<int64_t> pools;
+ for (auto i = 0; i < PyList_Size(pool_list); ++i) {
+ PyObject *pool_name = PyList_GET_ITEM(pool_list, i);
+ if (!PyUnicode_Check(pool_name)) {
+ derr << __func__ << " " << pool_name << " not a string" << dendl;
+ return nullptr;
+ }
+ auto pool_id = self->osdmap->lookup_pg_pool_name(
+ PyUnicode_AsUTF8(pool_name));
+ if (pool_id < 0) {
+ derr << __func__ << " pool '" << PyUnicode_AsUTF8(pool_name)
+ << "' does not exist" << dendl;
+ return nullptr;
+ }
+ pools.insert(pool_id);
+ }
+
+ dout(10) << __func__ << " osdmap " << self->osdmap << " inc " << incobj->inc
+ << " max_deviation " << max_deviation
+ << " max_iterations " << max_iterations
+ << " pools " << pools
+ << dendl;
+ PyThreadState *tstate = PyEval_SaveThread();
+ int r = self->osdmap->calc_pg_upmaps(g_ceph_context,
+ max_deviation,
+ max_iterations,
+ pools,
+ incobj->inc);
+ PyEval_RestoreThread(tstate);
+ dout(10) << __func__ << " r = " << r << dendl;
+ return PyLong_FromLong(r);
+}
+
+static PyObject *osdmap_map_pool_pgs_up(BasePyOSDMap* self, PyObject *args)
+{
+ int poolid;
+ if (!PyArg_ParseTuple(args, "i:map_pool_pgs_up",
+ &poolid)) {
+ return nullptr;
+ }
+ auto pi = self->osdmap->get_pg_pool(poolid);
+ if (!pi)
+ return nullptr;
+ map<pg_t,vector<int>> pm;
+ for (unsigned ps = 0; ps < pi->get_pg_num(); ++ps) {
+ pg_t pgid(ps, poolid);
+ self->osdmap->pg_to_up_acting_osds(pgid, &pm[pgid], nullptr, nullptr, nullptr);
+ }
+ PyFormatter f;
+ for (auto p : pm) {
+ string pg = stringify(p.first);
+ f.open_array_section(pg.c_str());
+ for (auto o : p.second) {
+ f.dump_int("osd", o);
+ }
+ f.close_section();
+ }
+ return f.get();
+}
+
+static int
+BasePyOSDMap_init(BasePyOSDMap *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *osdmap_capsule = nullptr;
+ static const char *kwlist[] = {"osdmap_capsule", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
+ const_cast<char**>(kwlist),
+ &osdmap_capsule)) {
+ ceph_abort();
+ return -1;
+ }
+ ceph_assert(PyObject_TypeCheck(osdmap_capsule, &PyCapsule_Type));
+
+ self->osdmap = (OSDMap*)PyCapsule_GetPointer(
+ osdmap_capsule, nullptr);
+ ceph_assert(self->osdmap);
+
+ return 0;
+}
+
+
+static void
+BasePyOSDMap_dealloc(BasePyOSDMap *self)
+{
+ if (self->osdmap) {
+ delete self->osdmap;
+ self->osdmap = nullptr;
+ } else {
+ derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
+ }
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *osdmap_pg_to_up_acting_osds(BasePyOSDMap *self, PyObject *args)
+{
+ int pool_id = 0;
+ int ps = 0;
+ if (!PyArg_ParseTuple(args, "ii:pg_to_up_acting_osds",
+ &pool_id, &ps)) {
+ return nullptr;
+ }
+
+ std::vector<int> up;
+ int up_primary;
+ std::vector<int> acting;
+ int acting_primary;
+ pg_t pg_id(ps, pool_id);
+ self->osdmap->pg_to_up_acting_osds(pg_id,
+ &up, &up_primary,
+ &acting, &acting_primary);
+
+ // (Ab)use PyFormatter as a convenient way to generate a dict
+ PyFormatter f;
+ f.dump_int("up_primary", up_primary);
+ f.dump_int("acting_primary", acting_primary);
+ f.open_array_section("up");
+ for (const auto &i : up) {
+ f.dump_int("osd", i);
+ }
+ f.close_section();
+ f.open_array_section("acting");
+ for (const auto &i : acting) {
+ f.dump_int("osd", i);
+ }
+ f.close_section();
+
+ return f.get();
+}
+
+static PyObject *osdmap_pool_raw_used_rate(BasePyOSDMap *self, PyObject *args)
+{
+ int pool_id = 0;
+ if (!PyArg_ParseTuple(args, "i:pool_raw_used_rate",
+ &pool_id)) {
+ return nullptr;
+ }
+
+ if (!self->osdmap->have_pg_pool(pool_id)) {
+ return nullptr;
+ }
+
+ float rate = self->osdmap->pool_raw_used_rate(pool_id);
+
+ return PyFloat_FromDouble(rate);
+}
+
+
+PyMethodDef BasePyOSDMap_methods[] = {
+ {"_get_epoch", (PyCFunction)osdmap_get_epoch, METH_NOARGS, "Get OSDMap epoch"},
+ {"_get_crush_version", (PyCFunction)osdmap_get_crush_version, METH_NOARGS,
+ "Get CRUSH version"},
+ {"_dump", (PyCFunction)osdmap_dump, METH_NOARGS, "Dump OSDMap::Incremental"},
+ {"_new_incremental", (PyCFunction)osdmap_new_incremental, METH_NOARGS,
+ "Create OSDMap::Incremental"},
+ {"_apply_incremental", (PyCFunction)osdmap_apply_incremental, METH_O,
+ "Apply OSDMap::Incremental and return the resulting OSDMap"},
+ {"_get_crush", (PyCFunction)osdmap_get_crush, METH_NOARGS, "Get CrushWrapper"},
+ {"_get_pools_by_take", (PyCFunction)osdmap_get_pools_by_take, METH_VARARGS,
+ "Get pools that have CRUSH rules that TAKE the given root"},
+ {"_calc_pg_upmaps", (PyCFunction)osdmap_calc_pg_upmaps, METH_VARARGS,
+ "Calculate new pg-upmap values"},
+ {"_map_pool_pgs_up", (PyCFunction)osdmap_map_pool_pgs_up, METH_VARARGS,
+ "Calculate up set mappings for all PGs in a pool"},
+ {"_pg_to_up_acting_osds", (PyCFunction)osdmap_pg_to_up_acting_osds, METH_VARARGS,
+ "Calculate up+acting OSDs for a PG ID"},
+ {"_pool_raw_used_rate", (PyCFunction)osdmap_pool_raw_used_rate, METH_VARARGS,
+ "Get raw space to logical space ratio"},
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject BasePyOSDMapType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ceph_module.BasePyOSDMap", /* tp_name */
+ sizeof(BasePyOSDMap), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BasePyOSDMap_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "Ceph OSDMap", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BasePyOSDMap_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BasePyOSDMap_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+// ----------
+
+
+static int
+BasePyOSDMapIncremental_init(BasePyOSDMapIncremental *self,
+ PyObject *args, PyObject *kwds)
+{
+ PyObject *inc_capsule = nullptr;
+ static const char *kwlist[] = {"inc_capsule", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
+ const_cast<char**>(kwlist),
+ &inc_capsule)) {
+ ceph_abort();
+ return -1;
+ }
+ ceph_assert(PyObject_TypeCheck(inc_capsule, &PyCapsule_Type));
+
+ self->inc = (OSDMap::Incremental*)PyCapsule_GetPointer(
+ inc_capsule, nullptr);
+ ceph_assert(self->inc);
+
+ return 0;
+}
+
+static void
+BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental *self)
+{
+ if (self->inc) {
+ delete self->inc;
+ self->inc = nullptr;
+ } else {
+ derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
+ }
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *osdmap_inc_get_epoch(BasePyOSDMapIncremental *self,
+ PyObject *obj)
+{
+ return PyLong_FromLong(self->inc->epoch);
+}
+
+static PyObject *osdmap_inc_dump(BasePyOSDMapIncremental *self,
+ PyObject *obj)
+{
+ PyFormatter f;
+ self->inc->dump(&f);
+ return f.get();
+}
+
+static int get_int_float_map(PyObject *obj, map<int,double> *out)
+{
+ PyObject *ls = PyDict_Items(obj);
+ for (int j = 0; j < PyList_Size(ls); ++j) {
+ PyObject *pair = PyList_GET_ITEM(ls, j);
+ if (!PyTuple_Check(pair)) {
+ derr << __func__ << " item " << j << " not a tuple" << dendl;
+ Py_DECREF(ls);
+ return -1;
+ }
+ int k;
+ double v;
+ if (!PyArg_ParseTuple(pair, "id:pair", &k, &v)) {
+ derr << __func__ << " item " << j << " not a size 2 tuple" << dendl;
+ Py_DECREF(ls);
+ return -1;
+ }
+ (*out)[k] = v;
+ }
+
+ Py_DECREF(ls);
+ return 0;
+}
+
+static PyObject *osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental *self,
+ PyObject *weightobj)
+{
+ map<int,double> wm;
+ if (get_int_float_map(weightobj, &wm) < 0) {
+ return nullptr;
+ }
+
+ for (auto i : wm) {
+ self->inc->new_weight[i.first] = std::max(0.0, std::min(1.0, i.second)) * 0x10000;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *osdmap_inc_set_compat_weight_set_weights(
+ BasePyOSDMapIncremental *self, PyObject *weightobj)
+{
+ map<int,double> wm;
+ if (get_int_float_map(weightobj, &wm) < 0) {
+ return nullptr;
+ }
+
+ CrushWrapper crush;
+ ceph_assert(self->inc->crush.length()); // see new_incremental
+ auto p = self->inc->crush.cbegin();
+ decode(crush, p);
+ crush.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS, 1);
+ for (auto i : wm) {
+ crush.choose_args_adjust_item_weightf(
+ g_ceph_context,
+ crush.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS),
+ i.first,
+ { i.second },
+ nullptr);
+ }
+ self->inc->crush.clear();
+ crush.encode(self->inc->crush, CEPH_FEATURES_ALL);
+ Py_RETURN_NONE;
+}
+
+PyMethodDef BasePyOSDMapIncremental_methods[] = {
+ {"_get_epoch", (PyCFunction)osdmap_inc_get_epoch, METH_NOARGS,
+ "Get OSDMap::Incremental epoch"},
+ {"_dump", (PyCFunction)osdmap_inc_dump, METH_NOARGS,
+ "Dump OSDMap::Incremental"},
+ {"_set_osd_reweights", (PyCFunction)osdmap_inc_set_osd_reweights,
+ METH_O, "Set osd reweight values"},
+ {"_set_crush_compat_weight_set_weights",
+ (PyCFunction)osdmap_inc_set_compat_weight_set_weights, METH_O,
+ "Set weight values in the pending CRUSH compat weight-set"},
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject BasePyOSDMapIncrementalType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ceph_module.BasePyOSDMapIncremental", /* tp_name */
+ sizeof(BasePyOSDMapIncremental), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BasePyOSDMapIncremental_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "Ceph OSDMapIncremental", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BasePyOSDMapIncremental_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BasePyOSDMapIncremental_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+
+// ----------
+
+static int
+BasePyCRUSH_init(BasePyCRUSH *self,
+ PyObject *args, PyObject *kwds)
+{
+ PyObject *crush_capsule = nullptr;
+ static const char *kwlist[] = {"crush_capsule", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
+ const_cast<char**>(kwlist),
+ &crush_capsule)) {
+ ceph_abort();
+ return -1;
+ }
+ ceph_assert(PyObject_TypeCheck(crush_capsule, &PyCapsule_Type));
+
+ auto ptr_ref = (std::shared_ptr<CrushWrapper>*)(
+ PyCapsule_GetPointer(crush_capsule, nullptr));
+
+ // We passed a pointer to a shared pointer, which is weird, but
+ // just enough to get it into the constructor: this is a real shared
+ // pointer construction now, and then we throw away that pointer to
+ // the shared pointer.
+ self->crush = *ptr_ref;
+ ceph_assert(self->crush);
+
+ return 0;
+}
+
+static void
+BasePyCRUSH_dealloc(BasePyCRUSH *self)
+{
+ self->crush.reset();
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *crush_dump(BasePyCRUSH *self, PyObject *obj)
+{
+ PyFormatter f;
+ self->crush->dump(&f);
+ return f.get();
+}
+
+static PyObject *crush_get_item_name(BasePyCRUSH *self, PyObject *args)
+{
+ int item;
+ if (!PyArg_ParseTuple(args, "i:get_item_name", &item)) {
+ return nullptr;
+ }
+ if (!self->crush->item_exists(item)) {
+ Py_RETURN_NONE;
+ }
+ return PyUnicode_FromString(self->crush->get_item_name(item));
+}
+
+static PyObject *crush_get_item_weight(BasePyCRUSH *self, PyObject *args)
+{
+ int item;
+ if (!PyArg_ParseTuple(args, "i:get_item_weight", &item)) {
+ return nullptr;
+ }
+ if (!self->crush->item_exists(item)) {
+ Py_RETURN_NONE;
+ }
+ return PyFloat_FromDouble(self->crush->get_item_weightf(item));
+}
+
+static PyObject *crush_find_roots(BasePyCRUSH *self)
+{
+ set<int> roots;
+ self->crush->find_roots(&roots);
+ PyFormatter f;
+ f.open_array_section("roots");
+ for (auto root : roots) {
+ f.dump_int("root", root);
+ }
+ f.close_section();
+ return f.get();
+}
+
+static PyObject *crush_find_takes(BasePyCRUSH *self, PyObject *obj)
+{
+ set<int> takes;
+ self->crush->find_takes(&takes);
+ PyFormatter f;
+ f.open_array_section("takes");
+ for (auto root : takes) {
+ f.dump_int("root", root);
+ }
+ f.close_section();
+ return f.get();
+}
+
+static PyObject *crush_get_take_weight_osd_map(BasePyCRUSH *self, PyObject *args)
+{
+ int root;
+ if (!PyArg_ParseTuple(args, "i:get_take_weight_osd_map",
+ &root)) {
+ return nullptr;
+ }
+ map<int,float> wmap;
+
+ if (!self->crush->item_exists(root)) {
+ return nullptr;
+ }
+
+ self->crush->get_take_weight_osd_map(root, &wmap);
+ PyFormatter f;
+ f.open_object_section("weights");
+ for (auto& p : wmap) {
+ string n = stringify(p.first); // ick
+ f.dump_float(n.c_str(), p.second);
+ }
+ f.close_section();
+ return f.get();
+}
+
+PyMethodDef BasePyCRUSH_methods[] = {
+ {"_dump", (PyCFunction)crush_dump, METH_NOARGS, "Dump map"},
+ {"_get_item_name", (PyCFunction)crush_get_item_name, METH_VARARGS,
+ "Get item name"},
+ {"_get_item_weight", (PyCFunction)crush_get_item_weight, METH_VARARGS,
+ "Get item weight"},
+ {"_find_roots", (PyCFunction)crush_find_roots, METH_NOARGS,
+ "Find all tree roots"},
+ {"_find_takes", (PyCFunction)crush_find_takes, METH_NOARGS,
+ "Find distinct TAKE roots"},
+ {"_get_take_weight_osd_map", (PyCFunction)crush_get_take_weight_osd_map,
+ METH_VARARGS, "Get OSD weight map for a given TAKE root node"},
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject BasePyCRUSHType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ceph_module.BasePyCRUSH", /* tp_name */
+ sizeof(BasePyCRUSH), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BasePyCRUSH_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "Ceph OSDMapIncremental", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BasePyCRUSH_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BasePyCRUSH_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};