]>
Commit | Line | Data |
---|---|---|
3efd9988 FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "Mgr.h" | |
5 | ||
6 | #include "osd/OSDMap.h" | |
7 | #include "common/errno.h" | |
8 | #include "common/version.h" | |
9 | #include "include/stringify.h" | |
10 | ||
11 | #include "PyOSDMap.h" | |
12 | #include "PyFormatter.h" | |
13 | #include "Gil.h" | |
14 | ||
15 | #define dout_context g_ceph_context | |
16 | #define dout_subsys ceph_subsys_mgr | |
17 | ||
18 | ||
19 | typedef struct { | |
20 | PyObject_HEAD | |
21 | OSDMap *osdmap; | |
22 | } BasePyOSDMap; | |
23 | ||
24 | typedef struct { | |
25 | PyObject_HEAD | |
26 | OSDMap::Incremental *inc; | |
27 | } BasePyOSDMapIncremental; | |
28 | ||
29 | typedef struct { | |
30 | PyObject_HEAD | |
11fdf7f2 | 31 | std::shared_ptr<CrushWrapper> crush; |
3efd9988 FG |
32 | } BasePyCRUSH; |
33 | ||
34 | // ---------- | |
35 | ||
36 | static PyObject *osdmap_get_epoch(BasePyOSDMap *self, PyObject *obj) | |
37 | { | |
9f95a23c | 38 | return PyLong_FromLong(self->osdmap->get_epoch()); |
3efd9988 FG |
39 | } |
40 | ||
41 | static PyObject *osdmap_get_crush_version(BasePyOSDMap* self, PyObject *obj) | |
42 | { | |
9f95a23c | 43 | return PyLong_FromLong(self->osdmap->get_crush_version()); |
3efd9988 FG |
44 | } |
45 | ||
46 | static PyObject *osdmap_dump(BasePyOSDMap* self, PyObject *obj) | |
47 | { | |
48 | PyFormatter f; | |
49 | self->osdmap->dump(&f); | |
50 | return f.get(); | |
51 | } | |
52 | ||
53 | static PyObject *osdmap_new_incremental(BasePyOSDMap *self, PyObject *obj) | |
54 | { | |
55 | OSDMap::Incremental *inc = new OSDMap::Incremental; | |
56 | ||
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 | |
61 | // be a no-op). | |
62 | self->osdmap->crush->encode(inc->crush, CEPH_FEATURES_ALL); | |
63 | dout(10) << __func__ << " " << inc << dendl; | |
64 | ||
65 | return construct_with_capsule("mgr_module", "OSDMapIncremental", | |
66 | (void*)(inc)); | |
67 | } | |
68 | ||
69 | static PyObject *osdmap_apply_incremental(BasePyOSDMap *self, | |
70 | BasePyOSDMapIncremental *incobj) | |
71 | { | |
72 | if (!PyObject_TypeCheck(incobj, &BasePyOSDMapIncrementalType)) { | |
73 | derr << "Wrong type in osdmap_apply_incremental!" << dendl; | |
74 | return nullptr; | |
75 | } | |
76 | ||
77 | bufferlist bl; | |
78 | self->osdmap->encode(bl, CEPH_FEATURES_ALL|CEPH_FEATURE_RESERVED); | |
79 | OSDMap *next = new OSDMap; | |
80 | next->decode(bl); | |
81 | next->apply_incremental(*(incobj->inc)); | |
82 | dout(10) << __func__ << " map " << self->osdmap << " inc " << incobj->inc | |
83 | << " next " << next << dendl; | |
84 | ||
85 | return construct_with_capsule("mgr_module", "OSDMap", (void*)next); | |
86 | } | |
87 | ||
88 | static PyObject *osdmap_get_crush(BasePyOSDMap* self, PyObject *obj) | |
89 | { | |
90 | return construct_with_capsule("mgr_module", "CRUSHMap", | |
91 | (void*)(&(self->osdmap->crush))); | |
92 | } | |
93 | ||
94 | static PyObject *osdmap_get_pools_by_take(BasePyOSDMap* self, PyObject *args) | |
95 | { | |
96 | int take; | |
97 | if (!PyArg_ParseTuple(args, "i:get_pools_by_take", | |
98 | &take)) { | |
99 | return nullptr; | |
100 | } | |
101 | ||
102 | PyFormatter f; | |
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); | |
107 | } | |
108 | } | |
109 | f.close_section(); | |
110 | return f.get(); | |
111 | } | |
112 | ||
113 | static PyObject *osdmap_calc_pg_upmaps(BasePyOSDMap* self, PyObject *args) | |
114 | { | |
115 | PyObject *pool_list; | |
116 | BasePyOSDMapIncremental *incobj; | |
92f5a8d4 | 117 | int max_deviation = 0; |
3efd9988 | 118 | int max_iterations = 0; |
92f5a8d4 | 119 | if (!PyArg_ParseTuple(args, "OiiO:calc_pg_upmaps", |
3efd9988 FG |
120 | &incobj, &max_deviation, |
121 | &max_iterations, &pool_list)) { | |
122 | return nullptr; | |
123 | } | |
94b18763 FG |
124 | if (!PyList_CheckExact(pool_list)) { |
125 | derr << __func__ << " pool_list not a list" << dendl; | |
126 | return nullptr; | |
127 | } | |
128 | set<int64_t> pools; | |
129 | for (auto i = 0; i < PyList_Size(pool_list); ++i) { | |
130 | PyObject *pool_name = PyList_GET_ITEM(pool_list, i); | |
9f95a23c | 131 | if (!PyUnicode_Check(pool_name)) { |
94b18763 FG |
132 | derr << __func__ << " " << pool_name << " not a string" << dendl; |
133 | return nullptr; | |
134 | } | |
135 | auto pool_id = self->osdmap->lookup_pg_pool_name( | |
9f95a23c | 136 | PyUnicode_AsUTF8(pool_name)); |
94b18763 | 137 | if (pool_id < 0) { |
9f95a23c | 138 | derr << __func__ << " pool '" << PyUnicode_AsUTF8(pool_name) |
94b18763 FG |
139 | << "' does not exist" << dendl; |
140 | return nullptr; | |
141 | } | |
142 | pools.insert(pool_id); | |
143 | } | |
3efd9988 FG |
144 | |
145 | dout(10) << __func__ << " osdmap " << self->osdmap << " inc " << incobj->inc | |
146 | << " max_deviation " << max_deviation | |
147 | << " max_iterations " << max_iterations | |
94b18763 | 148 | << " pools " << pools |
3efd9988 | 149 | << dendl; |
eafe8130 | 150 | PyThreadState *tstate = PyEval_SaveThread(); |
3efd9988 FG |
151 | int r = self->osdmap->calc_pg_upmaps(g_ceph_context, |
152 | max_deviation, | |
153 | max_iterations, | |
154 | pools, | |
155 | incobj->inc); | |
eafe8130 | 156 | PyEval_RestoreThread(tstate); |
3efd9988 | 157 | dout(10) << __func__ << " r = " << r << dendl; |
9f95a23c | 158 | return PyLong_FromLong(r); |
3efd9988 FG |
159 | } |
160 | ||
161 | static PyObject *osdmap_map_pool_pgs_up(BasePyOSDMap* self, PyObject *args) | |
162 | { | |
163 | int poolid; | |
164 | if (!PyArg_ParseTuple(args, "i:map_pool_pgs_up", | |
165 | &poolid)) { | |
166 | return nullptr; | |
167 | } | |
168 | auto pi = self->osdmap->get_pg_pool(poolid); | |
169 | if (!pi) | |
170 | return nullptr; | |
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); | |
175 | } | |
176 | PyFormatter f; | |
177 | for (auto p : pm) { | |
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); | |
182 | } | |
183 | f.close_section(); | |
184 | } | |
185 | return f.get(); | |
186 | } | |
187 | ||
188 | static int | |
189 | BasePyOSDMap_init(BasePyOSDMap *self, PyObject *args, PyObject *kwds) | |
190 | { | |
191 | PyObject *osdmap_capsule = nullptr; | |
192 | static const char *kwlist[] = {"osdmap_capsule", NULL}; | |
193 | ||
194 | if (! PyArg_ParseTupleAndKeywords(args, kwds, "O", | |
195 | const_cast<char**>(kwlist), | |
196 | &osdmap_capsule)) { | |
11fdf7f2 TL |
197 | ceph_abort(); |
198 | return -1; | |
3efd9988 | 199 | } |
11fdf7f2 | 200 | ceph_assert(PyObject_TypeCheck(osdmap_capsule, &PyCapsule_Type)); |
3efd9988 FG |
201 | |
202 | self->osdmap = (OSDMap*)PyCapsule_GetPointer( | |
203 | osdmap_capsule, nullptr); | |
11fdf7f2 | 204 | ceph_assert(self->osdmap); |
3efd9988 FG |
205 | |
206 | return 0; | |
207 | } | |
208 | ||
209 | ||
210 | static void | |
211 | BasePyOSDMap_dealloc(BasePyOSDMap *self) | |
212 | { | |
213 | if (self->osdmap) { | |
214 | delete self->osdmap; | |
215 | self->osdmap = nullptr; | |
216 | } else { | |
217 | derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl; | |
218 | } | |
219 | Py_TYPE(self)->tp_free(self); | |
220 | } | |
221 | ||
11fdf7f2 TL |
222 | static PyObject *osdmap_pg_to_up_acting_osds(BasePyOSDMap *self, PyObject *args) |
223 | { | |
224 | int pool_id = 0; | |
225 | int ps = 0; | |
226 | if (!PyArg_ParseTuple(args, "ii:pg_to_up_acting_osds", | |
227 | &pool_id, &ps)) { | |
228 | return nullptr; | |
229 | } | |
230 | ||
231 | std::vector<int> up; | |
232 | int up_primary; | |
233 | std::vector<int> acting; | |
234 | int acting_primary; | |
235 | pg_t pg_id(ps, pool_id); | |
236 | self->osdmap->pg_to_up_acting_osds(pg_id, | |
237 | &up, &up_primary, | |
238 | &acting, &acting_primary); | |
239 | ||
240 | // (Ab)use PyFormatter as a convenient way to generate a dict | |
241 | PyFormatter f; | |
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); | |
247 | } | |
248 | f.close_section(); | |
249 | f.open_array_section("acting"); | |
250 | for (const auto &i : acting) { | |
251 | f.dump_int("osd", i); | |
252 | } | |
253 | f.close_section(); | |
254 | ||
255 | return f.get(); | |
256 | } | |
257 | ||
258 | static PyObject *osdmap_pool_raw_used_rate(BasePyOSDMap *self, PyObject *args) | |
259 | { | |
260 | int pool_id = 0; | |
261 | if (!PyArg_ParseTuple(args, "i:pool_raw_used_rate", | |
262 | &pool_id)) { | |
263 | return nullptr; | |
264 | } | |
265 | ||
266 | if (!self->osdmap->have_pg_pool(pool_id)) { | |
267 | return nullptr; | |
268 | } | |
269 | ||
270 | float rate = self->osdmap->pool_raw_used_rate(pool_id); | |
271 | ||
272 | return PyFloat_FromDouble(rate); | |
273 | } | |
274 | ||
3efd9988 FG |
275 | |
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"}, | |
11fdf7f2 TL |
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"}, | |
3efd9988 FG |
296 | {NULL, NULL, 0, NULL} |
297 | }; | |
298 | ||
299 | PyTypeObject BasePyOSDMapType = { | |
300 | PyVarObject_HEAD_INIT(NULL, 0) | |
301 | "ceph_module.BasePyOSDMap", /* tp_name */ | |
302 | sizeof(BasePyOSDMap), /* tp_basicsize */ | |
303 | 0, /* tp_itemsize */ | |
304 | (destructor)BasePyOSDMap_dealloc, /* tp_dealloc */ | |
305 | 0, /* tp_print */ | |
306 | 0, /* tp_getattr */ | |
307 | 0, /* tp_setattr */ | |
308 | 0, /* tp_compare */ | |
309 | 0, /* tp_repr */ | |
310 | 0, /* tp_as_number */ | |
311 | 0, /* tp_as_sequence */ | |
312 | 0, /* tp_as_mapping */ | |
313 | 0, /* tp_hash */ | |
314 | 0, /* tp_call */ | |
315 | 0, /* tp_str */ | |
316 | 0, /* tp_getattro */ | |
317 | 0, /* tp_setattro */ | |
318 | 0, /* tp_as_buffer */ | |
319 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
320 | "Ceph OSDMap", /* tp_doc */ | |
321 | 0, /* tp_traverse */ | |
322 | 0, /* tp_clear */ | |
323 | 0, /* tp_richcompare */ | |
324 | 0, /* tp_weaklistoffset */ | |
325 | 0, /* tp_iter */ | |
326 | 0, /* tp_iternext */ | |
327 | BasePyOSDMap_methods, /* tp_methods */ | |
328 | 0, /* tp_members */ | |
329 | 0, /* tp_getset */ | |
330 | 0, /* tp_base */ | |
331 | 0, /* tp_dict */ | |
332 | 0, /* tp_descr_get */ | |
333 | 0, /* tp_descr_set */ | |
334 | 0, /* tp_dictoffset */ | |
335 | (initproc)BasePyOSDMap_init, /* tp_init */ | |
336 | 0, /* tp_alloc */ | |
337 | 0, /* tp_new */ | |
338 | }; | |
339 | ||
340 | // ---------- | |
341 | ||
342 | ||
343 | static int | |
344 | BasePyOSDMapIncremental_init(BasePyOSDMapIncremental *self, | |
345 | PyObject *args, PyObject *kwds) | |
346 | { | |
347 | PyObject *inc_capsule = nullptr; | |
348 | static const char *kwlist[] = {"inc_capsule", NULL}; | |
349 | ||
350 | if (! PyArg_ParseTupleAndKeywords(args, kwds, "O", | |
351 | const_cast<char**>(kwlist), | |
352 | &inc_capsule)) { | |
11fdf7f2 TL |
353 | ceph_abort(); |
354 | return -1; | |
3efd9988 | 355 | } |
11fdf7f2 | 356 | ceph_assert(PyObject_TypeCheck(inc_capsule, &PyCapsule_Type)); |
3efd9988 FG |
357 | |
358 | self->inc = (OSDMap::Incremental*)PyCapsule_GetPointer( | |
359 | inc_capsule, nullptr); | |
11fdf7f2 | 360 | ceph_assert(self->inc); |
3efd9988 FG |
361 | |
362 | return 0; | |
363 | } | |
364 | ||
365 | static void | |
366 | BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental *self) | |
367 | { | |
368 | if (self->inc) { | |
369 | delete self->inc; | |
370 | self->inc = nullptr; | |
371 | } else { | |
372 | derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl; | |
373 | } | |
374 | Py_TYPE(self)->tp_free(self); | |
375 | } | |
376 | ||
377 | static PyObject *osdmap_inc_get_epoch(BasePyOSDMapIncremental *self, | |
378 | PyObject *obj) | |
379 | { | |
9f95a23c | 380 | return PyLong_FromLong(self->inc->epoch); |
3efd9988 FG |
381 | } |
382 | ||
383 | static PyObject *osdmap_inc_dump(BasePyOSDMapIncremental *self, | |
384 | PyObject *obj) | |
385 | { | |
386 | PyFormatter f; | |
387 | self->inc->dump(&f); | |
388 | return f.get(); | |
389 | } | |
390 | ||
391 | static int get_int_float_map(PyObject *obj, map<int,double> *out) | |
392 | { | |
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; | |
398 | Py_DECREF(ls); | |
399 | return -1; | |
400 | } | |
401 | int k; | |
402 | double v; | |
403 | if (!PyArg_ParseTuple(pair, "id:pair", &k, &v)) { | |
404 | derr << __func__ << " item " << j << " not a size 2 tuple" << dendl; | |
405 | Py_DECREF(ls); | |
406 | return -1; | |
407 | } | |
408 | (*out)[k] = v; | |
409 | } | |
410 | ||
411 | Py_DECREF(ls); | |
412 | return 0; | |
413 | } | |
414 | ||
415 | static PyObject *osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental *self, | |
416 | PyObject *weightobj) | |
417 | { | |
418 | map<int,double> wm; | |
419 | if (get_int_float_map(weightobj, &wm) < 0) { | |
420 | return nullptr; | |
421 | } | |
422 | ||
423 | for (auto i : wm) { | |
424 | self->inc->new_weight[i.first] = std::max(0.0, std::min(1.0, i.second)) * 0x10000; | |
425 | } | |
426 | Py_RETURN_NONE; | |
427 | } | |
428 | ||
429 | static PyObject *osdmap_inc_set_compat_weight_set_weights( | |
430 | BasePyOSDMapIncremental *self, PyObject *weightobj) | |
431 | { | |
432 | map<int,double> wm; | |
433 | if (get_int_float_map(weightobj, &wm) < 0) { | |
434 | return nullptr; | |
435 | } | |
436 | ||
437 | CrushWrapper crush; | |
11fdf7f2 TL |
438 | ceph_assert(self->inc->crush.length()); // see new_incremental |
439 | auto p = self->inc->crush.cbegin(); | |
440 | decode(crush, p); | |
3efd9988 FG |
441 | crush.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS, 1); |
442 | for (auto i : wm) { | |
443 | crush.choose_args_adjust_item_weightf( | |
444 | g_ceph_context, | |
445 | crush.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS), | |
446 | i.first, | |
447 | { i.second }, | |
448 | nullptr); | |
449 | } | |
450 | self->inc->crush.clear(); | |
451 | crush.encode(self->inc->crush, CEPH_FEATURES_ALL); | |
452 | Py_RETURN_NONE; | |
453 | } | |
454 | ||
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} | |
466 | }; | |
467 | ||
468 | PyTypeObject BasePyOSDMapIncrementalType = { | |
469 | PyVarObject_HEAD_INIT(NULL, 0) | |
470 | "ceph_module.BasePyOSDMapIncremental", /* tp_name */ | |
471 | sizeof(BasePyOSDMapIncremental), /* tp_basicsize */ | |
472 | 0, /* tp_itemsize */ | |
473 | (destructor)BasePyOSDMapIncremental_dealloc, /* tp_dealloc */ | |
474 | 0, /* tp_print */ | |
475 | 0, /* tp_getattr */ | |
476 | 0, /* tp_setattr */ | |
477 | 0, /* tp_compare */ | |
478 | 0, /* tp_repr */ | |
479 | 0, /* tp_as_number */ | |
480 | 0, /* tp_as_sequence */ | |
481 | 0, /* tp_as_mapping */ | |
482 | 0, /* tp_hash */ | |
483 | 0, /* tp_call */ | |
484 | 0, /* tp_str */ | |
485 | 0, /* tp_getattro */ | |
486 | 0, /* tp_setattro */ | |
487 | 0, /* tp_as_buffer */ | |
488 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
489 | "Ceph OSDMapIncremental", /* tp_doc */ | |
490 | 0, /* tp_traverse */ | |
491 | 0, /* tp_clear */ | |
492 | 0, /* tp_richcompare */ | |
493 | 0, /* tp_weaklistoffset */ | |
494 | 0, /* tp_iter */ | |
495 | 0, /* tp_iternext */ | |
496 | BasePyOSDMapIncremental_methods, /* tp_methods */ | |
497 | 0, /* tp_members */ | |
498 | 0, /* tp_getset */ | |
499 | 0, /* tp_base */ | |
500 | 0, /* tp_dict */ | |
501 | 0, /* tp_descr_get */ | |
502 | 0, /* tp_descr_set */ | |
503 | 0, /* tp_dictoffset */ | |
504 | (initproc)BasePyOSDMapIncremental_init, /* tp_init */ | |
505 | 0, /* tp_alloc */ | |
506 | 0, /* tp_new */ | |
507 | }; | |
508 | ||
509 | ||
510 | // ---------- | |
511 | ||
512 | static int | |
513 | BasePyCRUSH_init(BasePyCRUSH *self, | |
514 | PyObject *args, PyObject *kwds) | |
515 | { | |
516 | PyObject *crush_capsule = nullptr; | |
517 | static const char *kwlist[] = {"crush_capsule", NULL}; | |
518 | ||
519 | if (! PyArg_ParseTupleAndKeywords(args, kwds, "O", | |
520 | const_cast<char**>(kwlist), | |
521 | &crush_capsule)) { | |
11fdf7f2 TL |
522 | ceph_abort(); |
523 | return -1; | |
3efd9988 | 524 | } |
11fdf7f2 | 525 | ceph_assert(PyObject_TypeCheck(crush_capsule, &PyCapsule_Type)); |
3efd9988 | 526 | |
11fdf7f2 | 527 | auto ptr_ref = (std::shared_ptr<CrushWrapper>*)( |
3efd9988 FG |
528 | PyCapsule_GetPointer(crush_capsule, nullptr)); |
529 | ||
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; | |
11fdf7f2 | 535 | ceph_assert(self->crush); |
3efd9988 FG |
536 | |
537 | return 0; | |
538 | } | |
539 | ||
540 | static void | |
541 | BasePyCRUSH_dealloc(BasePyCRUSH *self) | |
542 | { | |
543 | self->crush.reset(); | |
544 | Py_TYPE(self)->tp_free(self); | |
545 | } | |
546 | ||
547 | static PyObject *crush_dump(BasePyCRUSH *self, PyObject *obj) | |
548 | { | |
549 | PyFormatter f; | |
550 | self->crush->dump(&f); | |
551 | return f.get(); | |
552 | } | |
553 | ||
554 | static PyObject *crush_get_item_name(BasePyCRUSH *self, PyObject *args) | |
555 | { | |
556 | int item; | |
557 | if (!PyArg_ParseTuple(args, "i:get_item_name", &item)) { | |
558 | return nullptr; | |
559 | } | |
560 | if (!self->crush->item_exists(item)) { | |
561 | Py_RETURN_NONE; | |
562 | } | |
9f95a23c | 563 | return PyUnicode_FromString(self->crush->get_item_name(item)); |
3efd9988 FG |
564 | } |
565 | ||
566 | static PyObject *crush_get_item_weight(BasePyCRUSH *self, PyObject *args) | |
567 | { | |
568 | int item; | |
569 | if (!PyArg_ParseTuple(args, "i:get_item_weight", &item)) { | |
570 | return nullptr; | |
571 | } | |
572 | if (!self->crush->item_exists(item)) { | |
573 | Py_RETURN_NONE; | |
574 | } | |
575 | return PyFloat_FromDouble(self->crush->get_item_weightf(item)); | |
576 | } | |
577 | ||
578 | static PyObject *crush_find_takes(BasePyCRUSH *self, PyObject *obj) | |
579 | { | |
580 | set<int> takes; | |
581 | self->crush->find_takes(&takes); | |
582 | PyFormatter f; | |
583 | f.open_array_section("takes"); | |
584 | for (auto root : takes) { | |
585 | f.dump_int("root", root); | |
586 | } | |
587 | f.close_section(); | |
588 | return f.get(); | |
589 | } | |
590 | ||
591 | static PyObject *crush_get_take_weight_osd_map(BasePyCRUSH *self, PyObject *args) | |
592 | { | |
593 | int root; | |
594 | if (!PyArg_ParseTuple(args, "i:get_take_weight_osd_map", | |
595 | &root)) { | |
596 | return nullptr; | |
597 | } | |
598 | map<int,float> wmap; | |
599 | ||
600 | if (!self->crush->item_exists(root)) { | |
601 | return nullptr; | |
602 | } | |
603 | ||
604 | self->crush->get_take_weight_osd_map(root, &wmap); | |
605 | PyFormatter f; | |
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); | |
610 | } | |
611 | f.close_section(); | |
612 | return f.get(); | |
613 | } | |
614 | ||
615 | PyMethodDef BasePyCRUSH_methods[] = { | |
616 | {"_dump", (PyCFunction)crush_dump, METH_NOARGS, "Dump map"}, | |
617 | {"_get_item_name", (PyCFunction)crush_get_item_name, METH_VARARGS, | |
618 | "Get item name"}, | |
619 | {"_get_item_weight", (PyCFunction)crush_get_item_weight, METH_VARARGS, | |
620 | "Get item weight"}, | |
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} | |
626 | }; | |
627 | ||
628 | PyTypeObject BasePyCRUSHType = { | |
629 | PyVarObject_HEAD_INIT(NULL, 0) | |
630 | "ceph_module.BasePyCRUSH", /* tp_name */ | |
631 | sizeof(BasePyCRUSH), /* tp_basicsize */ | |
632 | 0, /* tp_itemsize */ | |
633 | (destructor)BasePyCRUSH_dealloc, /* tp_dealloc */ | |
634 | 0, /* tp_print */ | |
635 | 0, /* tp_getattr */ | |
636 | 0, /* tp_setattr */ | |
637 | 0, /* tp_compare */ | |
638 | 0, /* tp_repr */ | |
639 | 0, /* tp_as_number */ | |
640 | 0, /* tp_as_sequence */ | |
641 | 0, /* tp_as_mapping */ | |
642 | 0, /* tp_hash */ | |
643 | 0, /* tp_call */ | |
644 | 0, /* tp_str */ | |
645 | 0, /* tp_getattro */ | |
646 | 0, /* tp_setattro */ | |
647 | 0, /* tp_as_buffer */ | |
648 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
649 | "Ceph OSDMapIncremental", /* tp_doc */ | |
650 | 0, /* tp_traverse */ | |
651 | 0, /* tp_clear */ | |
652 | 0, /* tp_richcompare */ | |
653 | 0, /* tp_weaklistoffset */ | |
654 | 0, /* tp_iter */ | |
655 | 0, /* tp_iternext */ | |
656 | BasePyCRUSH_methods, /* tp_methods */ | |
657 | 0, /* tp_members */ | |
658 | 0, /* tp_getset */ | |
659 | 0, /* tp_base */ | |
660 | 0, /* tp_dict */ | |
661 | 0, /* tp_descr_get */ | |
662 | 0, /* tp_descr_set */ | |
663 | 0, /* tp_dictoffset */ | |
664 | (initproc)BasePyCRUSH_init, /* tp_init */ | |
665 | 0, /* tp_alloc */ | |
666 | 0, /* tp_new */ | |
667 | }; |