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 PyThreadState
*tstate
= PyEval_SaveThread();
151 int r
= self
->osdmap
->calc_pg_upmaps(g_ceph_context
,
156 PyEval_RestoreThread(tstate
);
157 dout(10) << __func__
<< " r = " << r
<< dendl
;
158 return PyInt_FromLong(r
);
161 static PyObject
*osdmap_map_pool_pgs_up(BasePyOSDMap
* self
, PyObject
*args
)
164 if (!PyArg_ParseTuple(args
, "i:map_pool_pgs_up",
168 auto pi
= self
->osdmap
->get_pg_pool(poolid
);
171 map
<pg_t
,vector
<int>> pm
;
172 for (unsigned ps
= 0; ps
< pi
->get_pg_num(); ++ps
) {
173 pg_t
pgid(ps
, poolid
);
174 self
->osdmap
->pg_to_up_acting_osds(pgid
, &pm
[pgid
], nullptr, nullptr, nullptr);
178 string pg
= stringify(p
.first
);
179 f
.open_array_section(pg
.c_str());
180 for (auto o
: p
.second
) {
181 f
.dump_int("osd", o
);
189 BasePyOSDMap_init(BasePyOSDMap
*self
, PyObject
*args
, PyObject
*kwds
)
191 PyObject
*osdmap_capsule
= nullptr;
192 static const char *kwlist
[] = {"osdmap_capsule", NULL
};
194 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
195 const_cast<char**>(kwlist
),
200 ceph_assert(PyObject_TypeCheck(osdmap_capsule
, &PyCapsule_Type
));
202 self
->osdmap
= (OSDMap
*)PyCapsule_GetPointer(
203 osdmap_capsule
, nullptr);
204 ceph_assert(self
->osdmap
);
211 BasePyOSDMap_dealloc(BasePyOSDMap
*self
)
215 self
->osdmap
= nullptr;
217 derr
<< "Destroying improperly initialized BasePyOSDMap " << self
<< dendl
;
219 Py_TYPE(self
)->tp_free(self
);
222 static PyObject
*osdmap_pg_to_up_acting_osds(BasePyOSDMap
*self
, PyObject
*args
)
226 if (!PyArg_ParseTuple(args
, "ii:pg_to_up_acting_osds",
233 std::vector
<int> acting
;
235 pg_t
pg_id(ps
, pool_id
);
236 self
->osdmap
->pg_to_up_acting_osds(pg_id
,
238 &acting
, &acting_primary
);
240 // (Ab)use PyFormatter as a convenient way to generate a dict
242 f
.dump_int("up_primary", up_primary
);
243 f
.dump_int("acting_primary", acting_primary
);
244 f
.open_array_section("up");
245 for (const auto &i
: up
) {
246 f
.dump_int("osd", i
);
249 f
.open_array_section("acting");
250 for (const auto &i
: acting
) {
251 f
.dump_int("osd", i
);
258 static PyObject
*osdmap_pool_raw_used_rate(BasePyOSDMap
*self
, PyObject
*args
)
261 if (!PyArg_ParseTuple(args
, "i:pool_raw_used_rate",
266 if (!self
->osdmap
->have_pg_pool(pool_id
)) {
270 float rate
= self
->osdmap
->pool_raw_used_rate(pool_id
);
272 return PyFloat_FromDouble(rate
);
276 PyMethodDef BasePyOSDMap_methods
[] = {
277 {"_get_epoch", (PyCFunction
)osdmap_get_epoch
, METH_NOARGS
, "Get OSDMap epoch"},
278 {"_get_crush_version", (PyCFunction
)osdmap_get_crush_version
, METH_NOARGS
,
279 "Get CRUSH version"},
280 {"_dump", (PyCFunction
)osdmap_dump
, METH_NOARGS
, "Dump OSDMap::Incremental"},
281 {"_new_incremental", (PyCFunction
)osdmap_new_incremental
, METH_NOARGS
,
282 "Create OSDMap::Incremental"},
283 {"_apply_incremental", (PyCFunction
)osdmap_apply_incremental
, METH_O
,
284 "Apply OSDMap::Incremental and return the resulting OSDMap"},
285 {"_get_crush", (PyCFunction
)osdmap_get_crush
, METH_NOARGS
, "Get CrushWrapper"},
286 {"_get_pools_by_take", (PyCFunction
)osdmap_get_pools_by_take
, METH_VARARGS
,
287 "Get pools that have CRUSH rules that TAKE the given root"},
288 {"_calc_pg_upmaps", (PyCFunction
)osdmap_calc_pg_upmaps
, METH_VARARGS
,
289 "Calculate new pg-upmap values"},
290 {"_map_pool_pgs_up", (PyCFunction
)osdmap_map_pool_pgs_up
, METH_VARARGS
,
291 "Calculate up set mappings for all PGs in a pool"},
292 {"_pg_to_up_acting_osds", (PyCFunction
)osdmap_pg_to_up_acting_osds
, METH_VARARGS
,
293 "Calculate up+acting OSDs for a PG ID"},
294 {"_pool_raw_used_rate", (PyCFunction
)osdmap_pool_raw_used_rate
, METH_VARARGS
,
295 "Get raw space to logical space ratio"},
296 {NULL
, NULL
, 0, NULL
}
299 PyTypeObject BasePyOSDMapType
= {
300 PyVarObject_HEAD_INIT(NULL
, 0)
301 "ceph_module.BasePyOSDMap", /* tp_name */
302 sizeof(BasePyOSDMap
), /* tp_basicsize */
304 (destructor
)BasePyOSDMap_dealloc
, /* tp_dealloc */
310 0, /* tp_as_number */
311 0, /* tp_as_sequence */
312 0, /* tp_as_mapping */
318 0, /* tp_as_buffer */
319 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
320 "Ceph OSDMap", /* tp_doc */
323 0, /* tp_richcompare */
324 0, /* tp_weaklistoffset */
327 BasePyOSDMap_methods
, /* tp_methods */
332 0, /* tp_descr_get */
333 0, /* tp_descr_set */
334 0, /* tp_dictoffset */
335 (initproc
)BasePyOSDMap_init
, /* tp_init */
344 BasePyOSDMapIncremental_init(BasePyOSDMapIncremental
*self
,
345 PyObject
*args
, PyObject
*kwds
)
347 PyObject
*inc_capsule
= nullptr;
348 static const char *kwlist
[] = {"inc_capsule", NULL
};
350 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
351 const_cast<char**>(kwlist
),
356 ceph_assert(PyObject_TypeCheck(inc_capsule
, &PyCapsule_Type
));
358 self
->inc
= (OSDMap::Incremental
*)PyCapsule_GetPointer(
359 inc_capsule
, nullptr);
360 ceph_assert(self
->inc
);
366 BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental
*self
)
372 derr
<< "Destroying improperly initialized BasePyOSDMap " << self
<< dendl
;
374 Py_TYPE(self
)->tp_free(self
);
377 static PyObject
*osdmap_inc_get_epoch(BasePyOSDMapIncremental
*self
,
380 return PyInt_FromLong(self
->inc
->epoch
);
383 static PyObject
*osdmap_inc_dump(BasePyOSDMapIncremental
*self
,
391 static int get_int_float_map(PyObject
*obj
, map
<int,double> *out
)
393 PyObject
*ls
= PyDict_Items(obj
);
394 for (int j
= 0; j
< PyList_Size(ls
); ++j
) {
395 PyObject
*pair
= PyList_GET_ITEM(ls
, j
);
396 if (!PyTuple_Check(pair
)) {
397 derr
<< __func__
<< " item " << j
<< " not a tuple" << dendl
;
403 if (!PyArg_ParseTuple(pair
, "id:pair", &k
, &v
)) {
404 derr
<< __func__
<< " item " << j
<< " not a size 2 tuple" << dendl
;
415 static PyObject
*osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental
*self
,
419 if (get_int_float_map(weightobj
, &wm
) < 0) {
424 self
->inc
->new_weight
[i
.first
] = std::max(0.0, std::min(1.0, i
.second
)) * 0x10000;
429 static PyObject
*osdmap_inc_set_compat_weight_set_weights(
430 BasePyOSDMapIncremental
*self
, PyObject
*weightobj
)
433 if (get_int_float_map(weightobj
, &wm
) < 0) {
438 ceph_assert(self
->inc
->crush
.length()); // see new_incremental
439 auto p
= self
->inc
->crush
.cbegin();
441 crush
.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS
, 1);
443 crush
.choose_args_adjust_item_weightf(
445 crush
.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS
),
450 self
->inc
->crush
.clear();
451 crush
.encode(self
->inc
->crush
, CEPH_FEATURES_ALL
);
455 PyMethodDef BasePyOSDMapIncremental_methods
[] = {
456 {"_get_epoch", (PyCFunction
)osdmap_inc_get_epoch
, METH_NOARGS
,
457 "Get OSDMap::Incremental epoch"},
458 {"_dump", (PyCFunction
)osdmap_inc_dump
, METH_NOARGS
,
459 "Dump OSDMap::Incremental"},
460 {"_set_osd_reweights", (PyCFunction
)osdmap_inc_set_osd_reweights
,
461 METH_O
, "Set osd reweight values"},
462 {"_set_crush_compat_weight_set_weights",
463 (PyCFunction
)osdmap_inc_set_compat_weight_set_weights
, METH_O
,
464 "Set weight values in the pending CRUSH compat weight-set"},
465 {NULL
, NULL
, 0, NULL
}
468 PyTypeObject BasePyOSDMapIncrementalType
= {
469 PyVarObject_HEAD_INIT(NULL
, 0)
470 "ceph_module.BasePyOSDMapIncremental", /* tp_name */
471 sizeof(BasePyOSDMapIncremental
), /* tp_basicsize */
473 (destructor
)BasePyOSDMapIncremental_dealloc
, /* tp_dealloc */
479 0, /* tp_as_number */
480 0, /* tp_as_sequence */
481 0, /* tp_as_mapping */
487 0, /* tp_as_buffer */
488 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
489 "Ceph OSDMapIncremental", /* tp_doc */
492 0, /* tp_richcompare */
493 0, /* tp_weaklistoffset */
496 BasePyOSDMapIncremental_methods
, /* tp_methods */
501 0, /* tp_descr_get */
502 0, /* tp_descr_set */
503 0, /* tp_dictoffset */
504 (initproc
)BasePyOSDMapIncremental_init
, /* tp_init */
513 BasePyCRUSH_init(BasePyCRUSH
*self
,
514 PyObject
*args
, PyObject
*kwds
)
516 PyObject
*crush_capsule
= nullptr;
517 static const char *kwlist
[] = {"crush_capsule", NULL
};
519 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
520 const_cast<char**>(kwlist
),
525 ceph_assert(PyObject_TypeCheck(crush_capsule
, &PyCapsule_Type
));
527 auto ptr_ref
= (std::shared_ptr
<CrushWrapper
>*)(
528 PyCapsule_GetPointer(crush_capsule
, nullptr));
530 // We passed a pointer to a shared pointer, which is weird, but
531 // just enough to get it into the constructor: this is a real shared
532 // pointer construction now, and then we throw away that pointer to
533 // the shared pointer.
534 self
->crush
= *ptr_ref
;
535 ceph_assert(self
->crush
);
541 BasePyCRUSH_dealloc(BasePyCRUSH
*self
)
544 Py_TYPE(self
)->tp_free(self
);
547 static PyObject
*crush_dump(BasePyCRUSH
*self
, PyObject
*obj
)
550 self
->crush
->dump(&f
);
554 static PyObject
*crush_get_item_name(BasePyCRUSH
*self
, PyObject
*args
)
557 if (!PyArg_ParseTuple(args
, "i:get_item_name", &item
)) {
560 if (!self
->crush
->item_exists(item
)) {
563 return PyString_FromString(self
->crush
->get_item_name(item
));
566 static PyObject
*crush_get_item_weight(BasePyCRUSH
*self
, PyObject
*args
)
569 if (!PyArg_ParseTuple(args
, "i:get_item_weight", &item
)) {
572 if (!self
->crush
->item_exists(item
)) {
575 return PyFloat_FromDouble(self
->crush
->get_item_weightf(item
));
578 static PyObject
*crush_find_takes(BasePyCRUSH
*self
, PyObject
*obj
)
581 self
->crush
->find_takes(&takes
);
583 f
.open_array_section("takes");
584 for (auto root
: takes
) {
585 f
.dump_int("root", root
);
591 static PyObject
*crush_get_take_weight_osd_map(BasePyCRUSH
*self
, PyObject
*args
)
594 if (!PyArg_ParseTuple(args
, "i:get_take_weight_osd_map",
600 if (!self
->crush
->item_exists(root
)) {
604 self
->crush
->get_take_weight_osd_map(root
, &wmap
);
606 f
.open_object_section("weights");
607 for (auto& p
: wmap
) {
608 string n
= stringify(p
.first
); // ick
609 f
.dump_float(n
.c_str(), p
.second
);
615 PyMethodDef BasePyCRUSH_methods
[] = {
616 {"_dump", (PyCFunction
)crush_dump
, METH_NOARGS
, "Dump map"},
617 {"_get_item_name", (PyCFunction
)crush_get_item_name
, METH_VARARGS
,
619 {"_get_item_weight", (PyCFunction
)crush_get_item_weight
, METH_VARARGS
,
621 {"_find_takes", (PyCFunction
)crush_find_takes
, METH_NOARGS
,
622 "Find distinct TAKE roots"},
623 {"_get_take_weight_osd_map", (PyCFunction
)crush_get_take_weight_osd_map
,
624 METH_VARARGS
, "Get OSD weight map for a given TAKE root node"},
625 {NULL
, NULL
, 0, NULL
}
628 PyTypeObject BasePyCRUSHType
= {
629 PyVarObject_HEAD_INIT(NULL
, 0)
630 "ceph_module.BasePyCRUSH", /* tp_name */
631 sizeof(BasePyCRUSH
), /* tp_basicsize */
633 (destructor
)BasePyCRUSH_dealloc
, /* tp_dealloc */
639 0, /* tp_as_number */
640 0, /* tp_as_sequence */
641 0, /* tp_as_mapping */
647 0, /* tp_as_buffer */
648 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
649 "Ceph OSDMapIncremental", /* tp_doc */
652 0, /* tp_richcompare */
653 0, /* tp_weaklistoffset */
656 BasePyCRUSH_methods
, /* tp_methods */
661 0, /* tp_descr_get */
662 0, /* tp_descr_set */
663 0, /* tp_dictoffset */
664 (initproc
)BasePyCRUSH_init
, /* tp_init */