1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "osd/OSDMap.h"
7 #include "common/errno.h"
8 #include "common/version.h"
9 #include "include/stringify.h"
12 #include "PyFormatter.h"
15 #define dout_context g_ceph_context
16 #define dout_subsys ceph_subsys_mgr
26 OSDMap::Incremental *inc;
27 } BasePyOSDMapIncremental;
31 ceph::shared_ptr<CrushWrapper> crush;
36 static PyObject *osdmap_get_epoch(BasePyOSDMap *self, PyObject *obj)
38 return PyInt_FromLong(self->osdmap->get_epoch());
41 static PyObject *osdmap_get_crush_version(BasePyOSDMap* self, PyObject *obj)
43 return PyInt_FromLong(self->osdmap->get_crush_version());
46 static PyObject *osdmap_dump(BasePyOSDMap* self, PyObject *obj)
49 self->osdmap->dump(&f);
53 static PyObject *osdmap_new_incremental(BasePyOSDMap *self, PyObject *obj)
55 OSDMap::Incremental *inc = new OSDMap::Incremental;
57 inc->fsid = self->osdmap->get_fsid();
58 inc->epoch = self->osdmap->get_epoch() + 1;
59 // always include latest crush map here... this is okay since we never
60 // actually use this map in the real world (and even if we did it would
62 self->osdmap->crush->encode(inc->crush, CEPH_FEATURES_ALL);
63 dout(10) << __func__ << " " << inc << dendl;
65 return construct_with_capsule("mgr_module", "OSDMapIncremental",
69 static PyObject *osdmap_apply_incremental(BasePyOSDMap *self,
70 BasePyOSDMapIncremental *incobj)
72 if (!PyObject_TypeCheck(incobj, &BasePyOSDMapIncrementalType)) {
73 derr << "Wrong type in osdmap_apply_incremental!" << dendl;
78 self->osdmap->encode(bl, CEPH_FEATURES_ALL|CEPH_FEATURE_RESERVED);
79 OSDMap *next = new OSDMap;
81 next->apply_incremental(*(incobj->inc));
82 dout(10) << __func__ << " map " << self->osdmap << " inc " << incobj->inc
83 << " next " << next << dendl;
85 return construct_with_capsule("mgr_module", "OSDMap", (void*)next);
88 static PyObject *osdmap_get_crush(BasePyOSDMap* self, PyObject *obj)
90 return construct_with_capsule("mgr_module", "CRUSHMap",
91 (void*)(&(self->osdmap->crush)));
94 static PyObject *osdmap_get_pools_by_take(BasePyOSDMap* self, PyObject *args)
97 if (!PyArg_ParseTuple(args, "i:get_pools_by_take",
103 f.open_array_section("pools");
104 for (auto& p : self->osdmap->get_pools()) {
105 if (self->osdmap->crush->rule_has_take(p.second.crush_rule, take)) {
106 f.dump_int("pool", p.first);
113 static PyObject *osdmap_calc_pg_upmaps(BasePyOSDMap* self, PyObject *args)
116 BasePyOSDMapIncremental *incobj;
117 double max_deviation = 0;
118 int max_iterations = 0;
119 if (!PyArg_ParseTuple(args, "OdiO:calc_pg_upmaps",
120 &incobj, &max_deviation,
121 &max_iterations, &pool_list)) {
125 dout(10) << __func__ << " osdmap " << self->osdmap << " inc " << incobj->inc
126 << " max_deviation " << max_deviation
127 << " max_iterations " << max_iterations
130 // FIXME: unpack pool_list and translate to pools set
131 int r = self->osdmap->calc_pg_upmaps(g_ceph_context,
136 dout(10) << __func__ << " r = " << r << dendl;
137 return PyInt_FromLong(r);
140 static PyObject *osdmap_map_pool_pgs_up(BasePyOSDMap* self, PyObject *args)
143 if (!PyArg_ParseTuple(args, "i:map_pool_pgs_up",
147 auto pi = self->osdmap->get_pg_pool(poolid);
150 map<pg_t,vector<int>> pm;
151 for (unsigned ps = 0; ps < pi->get_pg_num(); ++ps) {
152 pg_t pgid(ps, poolid);
153 self->osdmap->pg_to_up_acting_osds(pgid, &pm[pgid], nullptr, nullptr, nullptr);
157 string pg = stringify(p.first);
158 f.open_array_section(pg.c_str());
159 for (auto o : p.second) {
160 f.dump_int("osd", o);
168 BasePyOSDMap_init(BasePyOSDMap *self, PyObject *args, PyObject *kwds)
170 PyObject *osdmap_capsule = nullptr;
171 static const char *kwlist[] = {"osdmap_capsule", NULL};
173 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
174 const_cast<char**>(kwlist),
179 assert(PyObject_TypeCheck(osdmap_capsule, &PyCapsule_Type));
181 self->osdmap = (OSDMap*)PyCapsule_GetPointer(
182 osdmap_capsule, nullptr);
183 assert(self->osdmap);
190 BasePyOSDMap_dealloc(BasePyOSDMap *self)
194 self->osdmap = nullptr;
196 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
198 Py_TYPE(self)->tp_free(self);
202 PyMethodDef BasePyOSDMap_methods[] = {
203 {"_get_epoch", (PyCFunction)osdmap_get_epoch, METH_NOARGS, "Get OSDMap epoch"},
204 {"_get_crush_version", (PyCFunction)osdmap_get_crush_version, METH_NOARGS,
205 "Get CRUSH version"},
206 {"_dump", (PyCFunction)osdmap_dump, METH_NOARGS, "Dump OSDMap::Incremental"},
207 {"_new_incremental", (PyCFunction)osdmap_new_incremental, METH_NOARGS,
208 "Create OSDMap::Incremental"},
209 {"_apply_incremental", (PyCFunction)osdmap_apply_incremental, METH_O,
210 "Apply OSDMap::Incremental and return the resulting OSDMap"},
211 {"_get_crush", (PyCFunction)osdmap_get_crush, METH_NOARGS, "Get CrushWrapper"},
212 {"_get_pools_by_take", (PyCFunction)osdmap_get_pools_by_take, METH_VARARGS,
213 "Get pools that have CRUSH rules that TAKE the given root"},
214 {"_calc_pg_upmaps", (PyCFunction)osdmap_calc_pg_upmaps, METH_VARARGS,
215 "Calculate new pg-upmap values"},
216 {"_map_pool_pgs_up", (PyCFunction)osdmap_map_pool_pgs_up, METH_VARARGS,
217 "Calculate up set mappings for all PGs in a pool"},
218 {NULL, NULL, 0, NULL}
221 PyTypeObject BasePyOSDMapType = {
222 PyVarObject_HEAD_INIT(NULL, 0)
223 "ceph_module.BasePyOSDMap", /* tp_name */
224 sizeof(BasePyOSDMap), /* tp_basicsize */
226 (destructor)BasePyOSDMap_dealloc, /* tp_dealloc */
232 0, /* tp_as_number */
233 0, /* tp_as_sequence */
234 0, /* tp_as_mapping */
240 0, /* tp_as_buffer */
241 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
242 "Ceph OSDMap", /* tp_doc */
245 0, /* tp_richcompare */
246 0, /* tp_weaklistoffset */
249 BasePyOSDMap_methods, /* tp_methods */
254 0, /* tp_descr_get */
255 0, /* tp_descr_set */
256 0, /* tp_dictoffset */
257 (initproc)BasePyOSDMap_init, /* tp_init */
266 BasePyOSDMapIncremental_init(BasePyOSDMapIncremental *self,
267 PyObject *args, PyObject *kwds)
269 PyObject *inc_capsule = nullptr;
270 static const char *kwlist[] = {"inc_capsule", NULL};
272 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
273 const_cast<char**>(kwlist),
278 assert(PyObject_TypeCheck(inc_capsule, &PyCapsule_Type));
280 self->inc = (OSDMap::Incremental*)PyCapsule_GetPointer(
281 inc_capsule, nullptr);
288 BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental *self)
294 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
296 Py_TYPE(self)->tp_free(self);
299 static PyObject *osdmap_inc_get_epoch(BasePyOSDMapIncremental *self,
302 return PyInt_FromLong(self->inc->epoch);
305 static PyObject *osdmap_inc_dump(BasePyOSDMapIncremental *self,
313 static int get_int_float_map(PyObject *obj, map<int,double> *out)
315 PyObject *ls = PyDict_Items(obj);
316 for (int j = 0; j < PyList_Size(ls); ++j) {
317 PyObject *pair = PyList_GET_ITEM(ls, j);
318 if (!PyTuple_Check(pair)) {
319 derr << __func__ << " item " << j << " not a tuple" << dendl;
325 if (!PyArg_ParseTuple(pair, "id:pair", &k, &v)) {
326 derr << __func__ << " item " << j << " not a size 2 tuple" << dendl;
337 static PyObject *osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental *self,
341 if (get_int_float_map(weightobj, &wm) < 0) {
346 self->inc->new_weight[i.first] = std::max(0.0, std::min(1.0, i.second)) * 0x10000;
351 static PyObject *osdmap_inc_set_compat_weight_set_weights(
352 BasePyOSDMapIncremental *self, PyObject *weightobj)
355 if (get_int_float_map(weightobj, &wm) < 0) {
360 assert(self->inc->crush.length()); // see new_incremental
361 auto p = self->inc->crush.begin();
363 crush.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS, 1);
365 crush.choose_args_adjust_item_weightf(
367 crush.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS),
372 self->inc->crush.clear();
373 crush.encode(self->inc->crush, CEPH_FEATURES_ALL);
377 PyMethodDef BasePyOSDMapIncremental_methods[] = {
378 {"_get_epoch", (PyCFunction)osdmap_inc_get_epoch, METH_NOARGS,
379 "Get OSDMap::Incremental epoch"},
380 {"_dump", (PyCFunction)osdmap_inc_dump, METH_NOARGS,
381 "Dump OSDMap::Incremental"},
382 {"_set_osd_reweights", (PyCFunction)osdmap_inc_set_osd_reweights,
383 METH_O, "Set osd reweight values"},
384 {"_set_crush_compat_weight_set_weights",
385 (PyCFunction)osdmap_inc_set_compat_weight_set_weights, METH_O,
386 "Set weight values in the pending CRUSH compat weight-set"},
387 {NULL, NULL, 0, NULL}
390 PyTypeObject BasePyOSDMapIncrementalType = {
391 PyVarObject_HEAD_INIT(NULL, 0)
392 "ceph_module.BasePyOSDMapIncremental", /* tp_name */
393 sizeof(BasePyOSDMapIncremental), /* tp_basicsize */
395 (destructor)BasePyOSDMapIncremental_dealloc, /* tp_dealloc */
401 0, /* tp_as_number */
402 0, /* tp_as_sequence */
403 0, /* tp_as_mapping */
409 0, /* tp_as_buffer */
410 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
411 "Ceph OSDMapIncremental", /* tp_doc */
414 0, /* tp_richcompare */
415 0, /* tp_weaklistoffset */
418 BasePyOSDMapIncremental_methods, /* tp_methods */
423 0, /* tp_descr_get */
424 0, /* tp_descr_set */
425 0, /* tp_dictoffset */
426 (initproc)BasePyOSDMapIncremental_init, /* tp_init */
435 BasePyCRUSH_init(BasePyCRUSH *self,
436 PyObject *args, PyObject *kwds)
438 PyObject *crush_capsule = nullptr;
439 static const char *kwlist[] = {"crush_capsule", NULL};
441 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
442 const_cast<char**>(kwlist),
447 assert(PyObject_TypeCheck(crush_capsule, &PyCapsule_Type));
449 auto ptr_ref = (ceph::shared_ptr<CrushWrapper>*)(
450 PyCapsule_GetPointer(crush_capsule, nullptr));
452 // We passed a pointer to a shared pointer, which is weird, but
453 // just enough to get it into the constructor: this is a real shared
454 // pointer construction now, and then we throw away that pointer to
455 // the shared pointer.
456 self->crush = *ptr_ref;
463 BasePyCRUSH_dealloc(BasePyCRUSH *self)
466 Py_TYPE(self)->tp_free(self);
469 static PyObject *crush_dump(BasePyCRUSH *self, PyObject *obj)
472 self->crush->dump(&f);
476 static PyObject *crush_get_item_name(BasePyCRUSH *self, PyObject *args)
479 if (!PyArg_ParseTuple(args, "i:get_item_name", &item)) {
482 if (!self->crush->item_exists(item)) {
485 return PyString_FromString(self->crush->get_item_name(item));
488 static PyObject *crush_get_item_weight(BasePyCRUSH *self, PyObject *args)
491 if (!PyArg_ParseTuple(args, "i:get_item_weight", &item)) {
494 if (!self->crush->item_exists(item)) {
497 return PyFloat_FromDouble(self->crush->get_item_weightf(item));
500 static PyObject *crush_find_takes(BasePyCRUSH *self, PyObject *obj)
503 self->crush->find_takes(&takes);
505 f.open_array_section("takes");
506 for (auto root : takes) {
507 f.dump_int("root", root);
513 static PyObject *crush_get_take_weight_osd_map(BasePyCRUSH *self, PyObject *args)
516 if (!PyArg_ParseTuple(args, "i:get_take_weight_osd_map",
522 if (!self->crush->item_exists(root)) {
526 self->crush->get_take_weight_osd_map(root, &wmap);
528 f.open_object_section("weights");
529 for (auto& p : wmap) {
530 string n = stringify(p.first); // ick
531 f.dump_float(n.c_str(), p.second);
537 PyMethodDef BasePyCRUSH_methods[] = {
538 {"_dump", (PyCFunction)crush_dump, METH_NOARGS, "Dump map"},
539 {"_get_item_name", (PyCFunction)crush_get_item_name, METH_VARARGS,
541 {"_get_item_weight", (PyCFunction)crush_get_item_weight, METH_VARARGS,
543 {"_find_takes", (PyCFunction)crush_find_takes, METH_NOARGS,
544 "Find distinct TAKE roots"},
545 {"_get_take_weight_osd_map", (PyCFunction)crush_get_take_weight_osd_map,
546 METH_VARARGS, "Get OSD weight map for a given TAKE root node"},
547 {NULL, NULL, 0, NULL}
550 PyTypeObject BasePyCRUSHType = {
551 PyVarObject_HEAD_INIT(NULL, 0)
552 "ceph_module.BasePyCRUSH", /* tp_name */
553 sizeof(BasePyCRUSH), /* tp_basicsize */
555 (destructor)BasePyCRUSH_dealloc, /* tp_dealloc */
561 0, /* tp_as_number */
562 0, /* tp_as_sequence */
563 0, /* tp_as_mapping */
569 0, /* tp_as_buffer */
570 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
571 "Ceph OSDMapIncremental", /* tp_doc */
574 0, /* tp_richcompare */
575 0, /* tp_weaklistoffset */
578 BasePyCRUSH_methods, /* tp_methods */
583 0, /* tp_descr_get */
584 0, /* tp_descr_set */
585 0, /* tp_dictoffset */
586 (initproc)BasePyCRUSH_init, /* tp_init */