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 std::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
)) {
124 if (!PyList_CheckExact(pool_list
)) {
125 derr
<< __func__
<< " pool_list not a list" << dendl
;
129 for (auto i
= 0; i
< PyList_Size(pool_list
); ++i
) {
130 PyObject
*pool_name
= PyList_GET_ITEM(pool_list
, i
);
131 if (!PyString_Check(pool_name
)) {
132 derr
<< __func__
<< " " << pool_name
<< " not a string" << dendl
;
135 auto pool_id
= self
->osdmap
->lookup_pg_pool_name(
136 PyString_AsString(pool_name
));
138 derr
<< __func__
<< " pool '" << PyString_AsString(pool_name
)
139 << "' does not exist" << dendl
;
142 pools
.insert(pool_id
);
145 dout(10) << __func__
<< " osdmap " << self
->osdmap
<< " inc " << incobj
->inc
146 << " max_deviation " << max_deviation
147 << " max_iterations " << max_iterations
148 << " pools " << pools
150 int r
= self
->osdmap
->calc_pg_upmaps(g_ceph_context
,
155 dout(10) << __func__
<< " r = " << r
<< dendl
;
156 return PyInt_FromLong(r
);
159 static PyObject
*osdmap_map_pool_pgs_up(BasePyOSDMap
* self
, PyObject
*args
)
162 if (!PyArg_ParseTuple(args
, "i:map_pool_pgs_up",
166 auto pi
= self
->osdmap
->get_pg_pool(poolid
);
169 map
<pg_t
,vector
<int>> pm
;
170 for (unsigned ps
= 0; ps
< pi
->get_pg_num(); ++ps
) {
171 pg_t
pgid(ps
, poolid
);
172 self
->osdmap
->pg_to_up_acting_osds(pgid
, &pm
[pgid
], nullptr, nullptr, nullptr);
176 string pg
= stringify(p
.first
);
177 f
.open_array_section(pg
.c_str());
178 for (auto o
: p
.second
) {
179 f
.dump_int("osd", o
);
187 BasePyOSDMap_init(BasePyOSDMap
*self
, PyObject
*args
, PyObject
*kwds
)
189 PyObject
*osdmap_capsule
= nullptr;
190 static const char *kwlist
[] = {"osdmap_capsule", NULL
};
192 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
193 const_cast<char**>(kwlist
),
198 ceph_assert(PyObject_TypeCheck(osdmap_capsule
, &PyCapsule_Type
));
200 self
->osdmap
= (OSDMap
*)PyCapsule_GetPointer(
201 osdmap_capsule
, nullptr);
202 ceph_assert(self
->osdmap
);
209 BasePyOSDMap_dealloc(BasePyOSDMap
*self
)
213 self
->osdmap
= nullptr;
215 derr
<< "Destroying improperly initialized BasePyOSDMap " << self
<< dendl
;
217 Py_TYPE(self
)->tp_free(self
);
220 static PyObject
*osdmap_pg_to_up_acting_osds(BasePyOSDMap
*self
, PyObject
*args
)
224 if (!PyArg_ParseTuple(args
, "ii:pg_to_up_acting_osds",
231 std::vector
<int> acting
;
233 pg_t
pg_id(ps
, pool_id
);
234 self
->osdmap
->pg_to_up_acting_osds(pg_id
,
236 &acting
, &acting_primary
);
238 // (Ab)use PyFormatter as a convenient way to generate a dict
240 f
.dump_int("up_primary", up_primary
);
241 f
.dump_int("acting_primary", acting_primary
);
242 f
.open_array_section("up");
243 for (const auto &i
: up
) {
244 f
.dump_int("osd", i
);
247 f
.open_array_section("acting");
248 for (const auto &i
: acting
) {
249 f
.dump_int("osd", i
);
256 static PyObject
*osdmap_pool_raw_used_rate(BasePyOSDMap
*self
, PyObject
*args
)
259 if (!PyArg_ParseTuple(args
, "i:pool_raw_used_rate",
264 if (!self
->osdmap
->have_pg_pool(pool_id
)) {
268 float rate
= self
->osdmap
->pool_raw_used_rate(pool_id
);
270 return PyFloat_FromDouble(rate
);
274 PyMethodDef BasePyOSDMap_methods
[] = {
275 {"_get_epoch", (PyCFunction
)osdmap_get_epoch
, METH_NOARGS
, "Get OSDMap epoch"},
276 {"_get_crush_version", (PyCFunction
)osdmap_get_crush_version
, METH_NOARGS
,
277 "Get CRUSH version"},
278 {"_dump", (PyCFunction
)osdmap_dump
, METH_NOARGS
, "Dump OSDMap::Incremental"},
279 {"_new_incremental", (PyCFunction
)osdmap_new_incremental
, METH_NOARGS
,
280 "Create OSDMap::Incremental"},
281 {"_apply_incremental", (PyCFunction
)osdmap_apply_incremental
, METH_O
,
282 "Apply OSDMap::Incremental and return the resulting OSDMap"},
283 {"_get_crush", (PyCFunction
)osdmap_get_crush
, METH_NOARGS
, "Get CrushWrapper"},
284 {"_get_pools_by_take", (PyCFunction
)osdmap_get_pools_by_take
, METH_VARARGS
,
285 "Get pools that have CRUSH rules that TAKE the given root"},
286 {"_calc_pg_upmaps", (PyCFunction
)osdmap_calc_pg_upmaps
, METH_VARARGS
,
287 "Calculate new pg-upmap values"},
288 {"_map_pool_pgs_up", (PyCFunction
)osdmap_map_pool_pgs_up
, METH_VARARGS
,
289 "Calculate up set mappings for all PGs in a pool"},
290 {"_pg_to_up_acting_osds", (PyCFunction
)osdmap_pg_to_up_acting_osds
, METH_VARARGS
,
291 "Calculate up+acting OSDs for a PG ID"},
292 {"_pool_raw_used_rate", (PyCFunction
)osdmap_pool_raw_used_rate
, METH_VARARGS
,
293 "Get raw space to logical space ratio"},
294 {NULL
, NULL
, 0, NULL
}
297 PyTypeObject BasePyOSDMapType
= {
298 PyVarObject_HEAD_INIT(NULL
, 0)
299 "ceph_module.BasePyOSDMap", /* tp_name */
300 sizeof(BasePyOSDMap
), /* tp_basicsize */
302 (destructor
)BasePyOSDMap_dealloc
, /* tp_dealloc */
308 0, /* tp_as_number */
309 0, /* tp_as_sequence */
310 0, /* tp_as_mapping */
316 0, /* tp_as_buffer */
317 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
318 "Ceph OSDMap", /* tp_doc */
321 0, /* tp_richcompare */
322 0, /* tp_weaklistoffset */
325 BasePyOSDMap_methods
, /* tp_methods */
330 0, /* tp_descr_get */
331 0, /* tp_descr_set */
332 0, /* tp_dictoffset */
333 (initproc
)BasePyOSDMap_init
, /* tp_init */
342 BasePyOSDMapIncremental_init(BasePyOSDMapIncremental
*self
,
343 PyObject
*args
, PyObject
*kwds
)
345 PyObject
*inc_capsule
= nullptr;
346 static const char *kwlist
[] = {"inc_capsule", NULL
};
348 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
349 const_cast<char**>(kwlist
),
354 ceph_assert(PyObject_TypeCheck(inc_capsule
, &PyCapsule_Type
));
356 self
->inc
= (OSDMap::Incremental
*)PyCapsule_GetPointer(
357 inc_capsule
, nullptr);
358 ceph_assert(self
->inc
);
364 BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental
*self
)
370 derr
<< "Destroying improperly initialized BasePyOSDMap " << self
<< dendl
;
372 Py_TYPE(self
)->tp_free(self
);
375 static PyObject
*osdmap_inc_get_epoch(BasePyOSDMapIncremental
*self
,
378 return PyInt_FromLong(self
->inc
->epoch
);
381 static PyObject
*osdmap_inc_dump(BasePyOSDMapIncremental
*self
,
389 static int get_int_float_map(PyObject
*obj
, map
<int,double> *out
)
391 PyObject
*ls
= PyDict_Items(obj
);
392 for (int j
= 0; j
< PyList_Size(ls
); ++j
) {
393 PyObject
*pair
= PyList_GET_ITEM(ls
, j
);
394 if (!PyTuple_Check(pair
)) {
395 derr
<< __func__
<< " item " << j
<< " not a tuple" << dendl
;
401 if (!PyArg_ParseTuple(pair
, "id:pair", &k
, &v
)) {
402 derr
<< __func__
<< " item " << j
<< " not a size 2 tuple" << dendl
;
413 static PyObject
*osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental
*self
,
417 if (get_int_float_map(weightobj
, &wm
) < 0) {
422 self
->inc
->new_weight
[i
.first
] = std::max(0.0, std::min(1.0, i
.second
)) * 0x10000;
427 static PyObject
*osdmap_inc_set_compat_weight_set_weights(
428 BasePyOSDMapIncremental
*self
, PyObject
*weightobj
)
431 if (get_int_float_map(weightobj
, &wm
) < 0) {
436 ceph_assert(self
->inc
->crush
.length()); // see new_incremental
437 auto p
= self
->inc
->crush
.cbegin();
439 crush
.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS
, 1);
441 crush
.choose_args_adjust_item_weightf(
443 crush
.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS
),
448 self
->inc
->crush
.clear();
449 crush
.encode(self
->inc
->crush
, CEPH_FEATURES_ALL
);
453 PyMethodDef BasePyOSDMapIncremental_methods
[] = {
454 {"_get_epoch", (PyCFunction
)osdmap_inc_get_epoch
, METH_NOARGS
,
455 "Get OSDMap::Incremental epoch"},
456 {"_dump", (PyCFunction
)osdmap_inc_dump
, METH_NOARGS
,
457 "Dump OSDMap::Incremental"},
458 {"_set_osd_reweights", (PyCFunction
)osdmap_inc_set_osd_reweights
,
459 METH_O
, "Set osd reweight values"},
460 {"_set_crush_compat_weight_set_weights",
461 (PyCFunction
)osdmap_inc_set_compat_weight_set_weights
, METH_O
,
462 "Set weight values in the pending CRUSH compat weight-set"},
463 {NULL
, NULL
, 0, NULL
}
466 PyTypeObject BasePyOSDMapIncrementalType
= {
467 PyVarObject_HEAD_INIT(NULL
, 0)
468 "ceph_module.BasePyOSDMapIncremental", /* tp_name */
469 sizeof(BasePyOSDMapIncremental
), /* tp_basicsize */
471 (destructor
)BasePyOSDMapIncremental_dealloc
, /* tp_dealloc */
477 0, /* tp_as_number */
478 0, /* tp_as_sequence */
479 0, /* tp_as_mapping */
485 0, /* tp_as_buffer */
486 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
487 "Ceph OSDMapIncremental", /* tp_doc */
490 0, /* tp_richcompare */
491 0, /* tp_weaklistoffset */
494 BasePyOSDMapIncremental_methods
, /* tp_methods */
499 0, /* tp_descr_get */
500 0, /* tp_descr_set */
501 0, /* tp_dictoffset */
502 (initproc
)BasePyOSDMapIncremental_init
, /* tp_init */
511 BasePyCRUSH_init(BasePyCRUSH
*self
,
512 PyObject
*args
, PyObject
*kwds
)
514 PyObject
*crush_capsule
= nullptr;
515 static const char *kwlist
[] = {"crush_capsule", NULL
};
517 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
518 const_cast<char**>(kwlist
),
523 ceph_assert(PyObject_TypeCheck(crush_capsule
, &PyCapsule_Type
));
525 auto ptr_ref
= (std::shared_ptr
<CrushWrapper
>*)(
526 PyCapsule_GetPointer(crush_capsule
, nullptr));
528 // We passed a pointer to a shared pointer, which is weird, but
529 // just enough to get it into the constructor: this is a real shared
530 // pointer construction now, and then we throw away that pointer to
531 // the shared pointer.
532 self
->crush
= *ptr_ref
;
533 ceph_assert(self
->crush
);
539 BasePyCRUSH_dealloc(BasePyCRUSH
*self
)
542 Py_TYPE(self
)->tp_free(self
);
545 static PyObject
*crush_dump(BasePyCRUSH
*self
, PyObject
*obj
)
548 self
->crush
->dump(&f
);
552 static PyObject
*crush_get_item_name(BasePyCRUSH
*self
, PyObject
*args
)
555 if (!PyArg_ParseTuple(args
, "i:get_item_name", &item
)) {
558 if (!self
->crush
->item_exists(item
)) {
561 return PyString_FromString(self
->crush
->get_item_name(item
));
564 static PyObject
*crush_get_item_weight(BasePyCRUSH
*self
, PyObject
*args
)
567 if (!PyArg_ParseTuple(args
, "i:get_item_weight", &item
)) {
570 if (!self
->crush
->item_exists(item
)) {
573 return PyFloat_FromDouble(self
->crush
->get_item_weightf(item
));
576 static PyObject
*crush_find_takes(BasePyCRUSH
*self
, PyObject
*obj
)
579 self
->crush
->find_takes(&takes
);
581 f
.open_array_section("takes");
582 for (auto root
: takes
) {
583 f
.dump_int("root", root
);
589 static PyObject
*crush_get_take_weight_osd_map(BasePyCRUSH
*self
, PyObject
*args
)
592 if (!PyArg_ParseTuple(args
, "i:get_take_weight_osd_map",
598 if (!self
->crush
->item_exists(root
)) {
602 self
->crush
->get_take_weight_osd_map(root
, &wmap
);
604 f
.open_object_section("weights");
605 for (auto& p
: wmap
) {
606 string n
= stringify(p
.first
); // ick
607 f
.dump_float(n
.c_str(), p
.second
);
613 PyMethodDef BasePyCRUSH_methods
[] = {
614 {"_dump", (PyCFunction
)crush_dump
, METH_NOARGS
, "Dump map"},
615 {"_get_item_name", (PyCFunction
)crush_get_item_name
, METH_VARARGS
,
617 {"_get_item_weight", (PyCFunction
)crush_get_item_weight
, METH_VARARGS
,
619 {"_find_takes", (PyCFunction
)crush_find_takes
, METH_NOARGS
,
620 "Find distinct TAKE roots"},
621 {"_get_take_weight_osd_map", (PyCFunction
)crush_get_take_weight_osd_map
,
622 METH_VARARGS
, "Get OSD weight map for a given TAKE root node"},
623 {NULL
, NULL
, 0, NULL
}
626 PyTypeObject BasePyCRUSHType
= {
627 PyVarObject_HEAD_INIT(NULL
, 0)
628 "ceph_module.BasePyCRUSH", /* tp_name */
629 sizeof(BasePyCRUSH
), /* tp_basicsize */
631 (destructor
)BasePyCRUSH_dealloc
, /* tp_dealloc */
637 0, /* tp_as_number */
638 0, /* tp_as_sequence */
639 0, /* tp_as_mapping */
645 0, /* tp_as_buffer */
646 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
647 "Ceph OSDMapIncremental", /* tp_doc */
650 0, /* tp_richcompare */
651 0, /* tp_weaklistoffset */
654 BasePyCRUSH_methods
, /* tp_methods */
659 0, /* tp_descr_get */
660 0, /* tp_descr_set */
661 0, /* tp_dictoffset */
662 (initproc
)BasePyCRUSH_init
, /* tp_init */