]> git.proxmox.com Git - ceph.git/blob - ceph/src/mgr/PyOSDMap.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / mgr / PyOSDMap.cc
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
31 std::shared_ptr<CrushWrapper> crush;
32 } BasePyCRUSH;
33
34 // ----------
35
36 static PyObject *osdmap_get_epoch(BasePyOSDMap *self, PyObject *obj)
37 {
38 return PyInt_FromLong(self->osdmap->get_epoch());
39 }
40
41 static PyObject *osdmap_get_crush_version(BasePyOSDMap* self, PyObject *obj)
42 {
43 return PyInt_FromLong(self->osdmap->get_crush_version());
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;
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)) {
122 return nullptr;
123 }
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);
131 if (!PyString_Check(pool_name)) {
132 derr << __func__ << " " << pool_name << " not a string" << dendl;
133 return nullptr;
134 }
135 auto pool_id = self->osdmap->lookup_pg_pool_name(
136 PyString_AsString(pool_name));
137 if (pool_id < 0) {
138 derr << __func__ << " pool '" << PyString_AsString(pool_name)
139 << "' does not exist" << dendl;
140 return nullptr;
141 }
142 pools.insert(pool_id);
143 }
144
145 dout(10) << __func__ << " osdmap " << self->osdmap << " inc " << incobj->inc
146 << " max_deviation " << max_deviation
147 << " max_iterations " << max_iterations
148 << " pools " << pools
149 << dendl;
150 int r = self->osdmap->calc_pg_upmaps(g_ceph_context,
151 max_deviation,
152 max_iterations,
153 pools,
154 incobj->inc);
155 dout(10) << __func__ << " r = " << r << dendl;
156 return PyInt_FromLong(r);
157 }
158
159 static PyObject *osdmap_map_pool_pgs_up(BasePyOSDMap* self, PyObject *args)
160 {
161 int poolid;
162 if (!PyArg_ParseTuple(args, "i:map_pool_pgs_up",
163 &poolid)) {
164 return nullptr;
165 }
166 auto pi = self->osdmap->get_pg_pool(poolid);
167 if (!pi)
168 return nullptr;
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);
173 }
174 PyFormatter f;
175 for (auto p : pm) {
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);
180 }
181 f.close_section();
182 }
183 return f.get();
184 }
185
186 static int
187 BasePyOSDMap_init(BasePyOSDMap *self, PyObject *args, PyObject *kwds)
188 {
189 PyObject *osdmap_capsule = nullptr;
190 static const char *kwlist[] = {"osdmap_capsule", NULL};
191
192 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
193 const_cast<char**>(kwlist),
194 &osdmap_capsule)) {
195 ceph_abort();
196 return -1;
197 }
198 ceph_assert(PyObject_TypeCheck(osdmap_capsule, &PyCapsule_Type));
199
200 self->osdmap = (OSDMap*)PyCapsule_GetPointer(
201 osdmap_capsule, nullptr);
202 ceph_assert(self->osdmap);
203
204 return 0;
205 }
206
207
208 static void
209 BasePyOSDMap_dealloc(BasePyOSDMap *self)
210 {
211 if (self->osdmap) {
212 delete self->osdmap;
213 self->osdmap = nullptr;
214 } else {
215 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
216 }
217 Py_TYPE(self)->tp_free(self);
218 }
219
220 static PyObject *osdmap_pg_to_up_acting_osds(BasePyOSDMap *self, PyObject *args)
221 {
222 int pool_id = 0;
223 int ps = 0;
224 if (!PyArg_ParseTuple(args, "ii:pg_to_up_acting_osds",
225 &pool_id, &ps)) {
226 return nullptr;
227 }
228
229 std::vector<int> up;
230 int up_primary;
231 std::vector<int> acting;
232 int acting_primary;
233 pg_t pg_id(ps, pool_id);
234 self->osdmap->pg_to_up_acting_osds(pg_id,
235 &up, &up_primary,
236 &acting, &acting_primary);
237
238 // (Ab)use PyFormatter as a convenient way to generate a dict
239 PyFormatter f;
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);
245 }
246 f.close_section();
247 f.open_array_section("acting");
248 for (const auto &i : acting) {
249 f.dump_int("osd", i);
250 }
251 f.close_section();
252
253 return f.get();
254 }
255
256 static PyObject *osdmap_pool_raw_used_rate(BasePyOSDMap *self, PyObject *args)
257 {
258 int pool_id = 0;
259 if (!PyArg_ParseTuple(args, "i:pool_raw_used_rate",
260 &pool_id)) {
261 return nullptr;
262 }
263
264 if (!self->osdmap->have_pg_pool(pool_id)) {
265 return nullptr;
266 }
267
268 float rate = self->osdmap->pool_raw_used_rate(pool_id);
269
270 return PyFloat_FromDouble(rate);
271 }
272
273
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}
295 };
296
297 PyTypeObject BasePyOSDMapType = {
298 PyVarObject_HEAD_INIT(NULL, 0)
299 "ceph_module.BasePyOSDMap", /* tp_name */
300 sizeof(BasePyOSDMap), /* tp_basicsize */
301 0, /* tp_itemsize */
302 (destructor)BasePyOSDMap_dealloc, /* tp_dealloc */
303 0, /* tp_print */
304 0, /* tp_getattr */
305 0, /* tp_setattr */
306 0, /* tp_compare */
307 0, /* tp_repr */
308 0, /* tp_as_number */
309 0, /* tp_as_sequence */
310 0, /* tp_as_mapping */
311 0, /* tp_hash */
312 0, /* tp_call */
313 0, /* tp_str */
314 0, /* tp_getattro */
315 0, /* tp_setattro */
316 0, /* tp_as_buffer */
317 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
318 "Ceph OSDMap", /* tp_doc */
319 0, /* tp_traverse */
320 0, /* tp_clear */
321 0, /* tp_richcompare */
322 0, /* tp_weaklistoffset */
323 0, /* tp_iter */
324 0, /* tp_iternext */
325 BasePyOSDMap_methods, /* tp_methods */
326 0, /* tp_members */
327 0, /* tp_getset */
328 0, /* tp_base */
329 0, /* tp_dict */
330 0, /* tp_descr_get */
331 0, /* tp_descr_set */
332 0, /* tp_dictoffset */
333 (initproc)BasePyOSDMap_init, /* tp_init */
334 0, /* tp_alloc */
335 0, /* tp_new */
336 };
337
338 // ----------
339
340
341 static int
342 BasePyOSDMapIncremental_init(BasePyOSDMapIncremental *self,
343 PyObject *args, PyObject *kwds)
344 {
345 PyObject *inc_capsule = nullptr;
346 static const char *kwlist[] = {"inc_capsule", NULL};
347
348 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
349 const_cast<char**>(kwlist),
350 &inc_capsule)) {
351 ceph_abort();
352 return -1;
353 }
354 ceph_assert(PyObject_TypeCheck(inc_capsule, &PyCapsule_Type));
355
356 self->inc = (OSDMap::Incremental*)PyCapsule_GetPointer(
357 inc_capsule, nullptr);
358 ceph_assert(self->inc);
359
360 return 0;
361 }
362
363 static void
364 BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental *self)
365 {
366 if (self->inc) {
367 delete self->inc;
368 self->inc = nullptr;
369 } else {
370 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
371 }
372 Py_TYPE(self)->tp_free(self);
373 }
374
375 static PyObject *osdmap_inc_get_epoch(BasePyOSDMapIncremental *self,
376 PyObject *obj)
377 {
378 return PyInt_FromLong(self->inc->epoch);
379 }
380
381 static PyObject *osdmap_inc_dump(BasePyOSDMapIncremental *self,
382 PyObject *obj)
383 {
384 PyFormatter f;
385 self->inc->dump(&f);
386 return f.get();
387 }
388
389 static int get_int_float_map(PyObject *obj, map<int,double> *out)
390 {
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;
396 Py_DECREF(ls);
397 return -1;
398 }
399 int k;
400 double v;
401 if (!PyArg_ParseTuple(pair, "id:pair", &k, &v)) {
402 derr << __func__ << " item " << j << " not a size 2 tuple" << dendl;
403 Py_DECREF(ls);
404 return -1;
405 }
406 (*out)[k] = v;
407 }
408
409 Py_DECREF(ls);
410 return 0;
411 }
412
413 static PyObject *osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental *self,
414 PyObject *weightobj)
415 {
416 map<int,double> wm;
417 if (get_int_float_map(weightobj, &wm) < 0) {
418 return nullptr;
419 }
420
421 for (auto i : wm) {
422 self->inc->new_weight[i.first] = std::max(0.0, std::min(1.0, i.second)) * 0x10000;
423 }
424 Py_RETURN_NONE;
425 }
426
427 static PyObject *osdmap_inc_set_compat_weight_set_weights(
428 BasePyOSDMapIncremental *self, PyObject *weightobj)
429 {
430 map<int,double> wm;
431 if (get_int_float_map(weightobj, &wm) < 0) {
432 return nullptr;
433 }
434
435 CrushWrapper crush;
436 ceph_assert(self->inc->crush.length()); // see new_incremental
437 auto p = self->inc->crush.cbegin();
438 decode(crush, p);
439 crush.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS, 1);
440 for (auto i : wm) {
441 crush.choose_args_adjust_item_weightf(
442 g_ceph_context,
443 crush.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS),
444 i.first,
445 { i.second },
446 nullptr);
447 }
448 self->inc->crush.clear();
449 crush.encode(self->inc->crush, CEPH_FEATURES_ALL);
450 Py_RETURN_NONE;
451 }
452
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}
464 };
465
466 PyTypeObject BasePyOSDMapIncrementalType = {
467 PyVarObject_HEAD_INIT(NULL, 0)
468 "ceph_module.BasePyOSDMapIncremental", /* tp_name */
469 sizeof(BasePyOSDMapIncremental), /* tp_basicsize */
470 0, /* tp_itemsize */
471 (destructor)BasePyOSDMapIncremental_dealloc, /* tp_dealloc */
472 0, /* tp_print */
473 0, /* tp_getattr */
474 0, /* tp_setattr */
475 0, /* tp_compare */
476 0, /* tp_repr */
477 0, /* tp_as_number */
478 0, /* tp_as_sequence */
479 0, /* tp_as_mapping */
480 0, /* tp_hash */
481 0, /* tp_call */
482 0, /* tp_str */
483 0, /* tp_getattro */
484 0, /* tp_setattro */
485 0, /* tp_as_buffer */
486 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
487 "Ceph OSDMapIncremental", /* tp_doc */
488 0, /* tp_traverse */
489 0, /* tp_clear */
490 0, /* tp_richcompare */
491 0, /* tp_weaklistoffset */
492 0, /* tp_iter */
493 0, /* tp_iternext */
494 BasePyOSDMapIncremental_methods, /* tp_methods */
495 0, /* tp_members */
496 0, /* tp_getset */
497 0, /* tp_base */
498 0, /* tp_dict */
499 0, /* tp_descr_get */
500 0, /* tp_descr_set */
501 0, /* tp_dictoffset */
502 (initproc)BasePyOSDMapIncremental_init, /* tp_init */
503 0, /* tp_alloc */
504 0, /* tp_new */
505 };
506
507
508 // ----------
509
510 static int
511 BasePyCRUSH_init(BasePyCRUSH *self,
512 PyObject *args, PyObject *kwds)
513 {
514 PyObject *crush_capsule = nullptr;
515 static const char *kwlist[] = {"crush_capsule", NULL};
516
517 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
518 const_cast<char**>(kwlist),
519 &crush_capsule)) {
520 ceph_abort();
521 return -1;
522 }
523 ceph_assert(PyObject_TypeCheck(crush_capsule, &PyCapsule_Type));
524
525 auto ptr_ref = (std::shared_ptr<CrushWrapper>*)(
526 PyCapsule_GetPointer(crush_capsule, nullptr));
527
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);
534
535 return 0;
536 }
537
538 static void
539 BasePyCRUSH_dealloc(BasePyCRUSH *self)
540 {
541 self->crush.reset();
542 Py_TYPE(self)->tp_free(self);
543 }
544
545 static PyObject *crush_dump(BasePyCRUSH *self, PyObject *obj)
546 {
547 PyFormatter f;
548 self->crush->dump(&f);
549 return f.get();
550 }
551
552 static PyObject *crush_get_item_name(BasePyCRUSH *self, PyObject *args)
553 {
554 int item;
555 if (!PyArg_ParseTuple(args, "i:get_item_name", &item)) {
556 return nullptr;
557 }
558 if (!self->crush->item_exists(item)) {
559 Py_RETURN_NONE;
560 }
561 return PyString_FromString(self->crush->get_item_name(item));
562 }
563
564 static PyObject *crush_get_item_weight(BasePyCRUSH *self, PyObject *args)
565 {
566 int item;
567 if (!PyArg_ParseTuple(args, "i:get_item_weight", &item)) {
568 return nullptr;
569 }
570 if (!self->crush->item_exists(item)) {
571 Py_RETURN_NONE;
572 }
573 return PyFloat_FromDouble(self->crush->get_item_weightf(item));
574 }
575
576 static PyObject *crush_find_takes(BasePyCRUSH *self, PyObject *obj)
577 {
578 set<int> takes;
579 self->crush->find_takes(&takes);
580 PyFormatter f;
581 f.open_array_section("takes");
582 for (auto root : takes) {
583 f.dump_int("root", root);
584 }
585 f.close_section();
586 return f.get();
587 }
588
589 static PyObject *crush_get_take_weight_osd_map(BasePyCRUSH *self, PyObject *args)
590 {
591 int root;
592 if (!PyArg_ParseTuple(args, "i:get_take_weight_osd_map",
593 &root)) {
594 return nullptr;
595 }
596 map<int,float> wmap;
597
598 if (!self->crush->item_exists(root)) {
599 return nullptr;
600 }
601
602 self->crush->get_take_weight_osd_map(root, &wmap);
603 PyFormatter f;
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);
608 }
609 f.close_section();
610 return f.get();
611 }
612
613 PyMethodDef BasePyCRUSH_methods[] = {
614 {"_dump", (PyCFunction)crush_dump, METH_NOARGS, "Dump map"},
615 {"_get_item_name", (PyCFunction)crush_get_item_name, METH_VARARGS,
616 "Get item name"},
617 {"_get_item_weight", (PyCFunction)crush_get_item_weight, METH_VARARGS,
618 "Get item weight"},
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}
624 };
625
626 PyTypeObject BasePyCRUSHType = {
627 PyVarObject_HEAD_INIT(NULL, 0)
628 "ceph_module.BasePyCRUSH", /* tp_name */
629 sizeof(BasePyCRUSH), /* tp_basicsize */
630 0, /* tp_itemsize */
631 (destructor)BasePyCRUSH_dealloc, /* tp_dealloc */
632 0, /* tp_print */
633 0, /* tp_getattr */
634 0, /* tp_setattr */
635 0, /* tp_compare */
636 0, /* tp_repr */
637 0, /* tp_as_number */
638 0, /* tp_as_sequence */
639 0, /* tp_as_mapping */
640 0, /* tp_hash */
641 0, /* tp_call */
642 0, /* tp_str */
643 0, /* tp_getattro */
644 0, /* tp_setattro */
645 0, /* tp_as_buffer */
646 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
647 "Ceph OSDMapIncremental", /* tp_doc */
648 0, /* tp_traverse */
649 0, /* tp_clear */
650 0, /* tp_richcompare */
651 0, /* tp_weaklistoffset */
652 0, /* tp_iter */
653 0, /* tp_iternext */
654 BasePyCRUSH_methods, /* tp_methods */
655 0, /* tp_members */
656 0, /* tp_getset */
657 0, /* tp_base */
658 0, /* tp_dict */
659 0, /* tp_descr_get */
660 0, /* tp_descr_set */
661 0, /* tp_dictoffset */
662 (initproc)BasePyCRUSH_init, /* tp_init */
663 0, /* tp_alloc */
664 0, /* tp_new */
665 };