1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
7 * Copyright (C) 2014 Red Hat <contact@redhat.com>
9 * Author: Loic Dachary <loic@dachary.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library Public License for more details.
24 #include <gtest/gtest.h>
26 #include "include/stringify.h"
27 #include "common/ceph_argparse.h"
28 #include "global/global_init.h"
29 #include "global/global_context.h"
30 #include "include/Context.h"
31 #include "osd/osd_types.h"
33 #include "crush/CrushWrapper.h"
35 TEST(CrushWrapper
, get_immediate_parent
) {
36 CrushWrapper
*c
= new CrushWrapper
;
38 const int ROOT_TYPE
= 1;
39 c
->set_type_name(ROOT_TYPE
, "root");
40 const int OSD_TYPE
= 0;
41 c
->set_type_name(OSD_TYPE
, "osd");
44 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
45 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
46 c
->set_item_name(rootno
, "default");
50 pair
<string
,string
> loc
;
52 loc
= c
->get_immediate_parent(item
, &ret
);
53 EXPECT_EQ(-ENOENT
, ret
);
56 map
<string
,string
> loc
;
57 loc
["root"] = "default";
59 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
63 loc
= c
->get_immediate_parent(item
, &ret
);
65 EXPECT_EQ("root", loc
.first
);
66 EXPECT_EQ("default", loc
.second
);
71 TEST(CrushWrapper
, move_bucket
) {
72 CrushWrapper
*c
= new CrushWrapper
;
74 const int ROOT_TYPE
= 2;
75 c
->set_type_name(ROOT_TYPE
, "root");
76 const int HOST_TYPE
= 1;
77 c
->set_type_name(HOST_TYPE
, "host");
78 const int OSD_TYPE
= 0;
79 c
->set_type_name(OSD_TYPE
, "osd");
82 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
83 ROOT_TYPE
, 0, NULL
, NULL
, &root0
));
84 EXPECT_EQ(0, c
->set_item_name(root0
, "root0"));
87 map
<string
,string
> loc
;
88 loc
["root"] = "root0";
89 loc
["host"] = "host0";
92 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
95 int host0
= c
->get_item_id("host0");
98 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
99 ROOT_TYPE
, 0, NULL
, NULL
, &root1
));
100 EXPECT_EQ(0, c
->set_item_name(root1
, "root1"));
102 map
<string
,string
> loc
;
103 loc
["root"] = "root1";
105 // 0 is not a valid bucket number, must be negative
106 EXPECT_EQ(-EINVAL
, c
->move_bucket(g_ceph_context
, 0, loc
));
107 // -100 is not an existing bucket
108 EXPECT_EQ(-ENOENT
, c
->move_bucket(g_ceph_context
, -100, loc
));
109 // move host0 from root0 to root1
111 pair
<string
,string
> loc
;
113 loc
= c
->get_immediate_parent(host0
, &ret
);
115 EXPECT_EQ("root", loc
.first
);
116 EXPECT_EQ("root0", loc
.second
);
118 EXPECT_EQ(0, c
->move_bucket(g_ceph_context
, host0
, loc
));
120 pair
<string
,string
> loc
;
122 loc
= c
->get_immediate_parent(host0
, &ret
);
124 EXPECT_EQ("root", loc
.first
);
125 EXPECT_EQ("root1", loc
.second
);
131 TEST(CrushWrapper
, rename_bucket_or_item
) {
132 CrushWrapper
*c
= new CrushWrapper
;
134 const int ROOT_TYPE
= 2;
135 c
->set_type_name(ROOT_TYPE
, "root");
136 const int HOST_TYPE
= 1;
137 c
->set_type_name(HOST_TYPE
, "host");
138 const int OSD_TYPE
= 0;
139 c
->set_type_name(OSD_TYPE
, "osd");
142 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
143 ROOT_TYPE
, 0, NULL
, NULL
, &root0
));
144 EXPECT_EQ(0, c
->set_item_name(root0
, "root0"));
148 map
<string
,string
> loc
;
149 loc
["root"] = "root0";
150 loc
["host"] = "host0";
152 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
157 map
<string
,string
> loc
;
158 loc
["root"] = "root0";
159 loc
["host"] = "host1";
161 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
166 EXPECT_EQ(-EINVAL
, c
->can_rename_item("host0", "????", &ss
));
167 EXPECT_EQ(-EINVAL
, c
->rename_item("host0", "????", &ss
));
168 EXPECT_EQ(-EINVAL
, c
->can_rename_bucket("host0", "????", &ss
));
169 EXPECT_EQ(-EINVAL
, c
->rename_bucket("host0", "????", &ss
));
171 EXPECT_EQ(-EEXIST
, c
->can_rename_item("host0", "host1", &ss
));
172 EXPECT_EQ(-EEXIST
, c
->rename_item("host0", "host1", &ss
));
173 EXPECT_EQ(-EEXIST
, c
->can_rename_bucket("host0", "host1", &ss
));
174 EXPECT_EQ(-EEXIST
, c
->rename_bucket("host0", "host1", &ss
));
176 EXPECT_EQ(-EALREADY
, c
->can_rename_item("gone", "host1", &ss
));
177 EXPECT_EQ(-EALREADY
, c
->rename_item("gone", "host1", &ss
));
178 EXPECT_EQ(-EALREADY
, c
->can_rename_bucket("gone", "host1", &ss
));
179 EXPECT_EQ(-EALREADY
, c
->rename_bucket("gone", "host1", &ss
));
181 EXPECT_EQ(-ENOENT
, c
->can_rename_item("doesnotexist", "somethingelse", &ss
));
182 EXPECT_EQ(-ENOENT
, c
->rename_item("doesnotexist", "somethingelse", &ss
));
183 EXPECT_EQ(-ENOENT
, c
->can_rename_bucket("doesnotexist", "somethingelse", &ss
));
184 EXPECT_EQ(-ENOENT
, c
->rename_bucket("doesnotexist", "somethingelse", &ss
));
186 EXPECT_EQ(-ENOTDIR
, c
->can_rename_bucket("osd.1", "somethingelse", &ss
));
187 EXPECT_EQ(-ENOTDIR
, c
->rename_bucket("osd.1", "somethingelse", &ss
));
189 int host0id
= c
->get_item_id("host0");
190 EXPECT_EQ(0, c
->rename_bucket("host0", "host0renamed", &ss
));
191 EXPECT_EQ(host0id
, c
->get_item_id("host0renamed"));
193 int osd0id
= c
->get_item_id("osd0");
194 EXPECT_EQ(0, c
->rename_item("osd.0", "osd0renamed", &ss
));
195 EXPECT_EQ(osd0id
, c
->get_item_id("osd0renamed"));
200 TEST(CrushWrapper
, check_item_loc
) {
201 CrushWrapper
*c
= new CrushWrapper
;
203 float expected_weight
= 1.0;
205 // fail if loc is empty
208 map
<string
,string
> loc
;
209 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
212 const int ROOT_TYPE
= 2;
213 c
->set_type_name(ROOT_TYPE
, "root");
214 const int HOST_TYPE
= 1;
215 c
->set_type_name(HOST_TYPE
, "host");
216 const int OSD_TYPE
= 0;
217 c
->set_type_name(OSD_TYPE
, "osd");
220 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
221 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
222 c
->set_item_name(rootno
, "default");
224 // fail because the item is not found at the specified location
227 map
<string
,string
> loc
;
228 loc
["root"] = "default";
229 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
231 // fail because the bucket name does not match an existing bucket
234 map
<string
,string
> loc
;
235 loc
["root"] = "default";
236 const string
HOST("host0");
238 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
240 const string
OSD("osd.0");
242 map
<string
,string
> loc
;
243 loc
["root"] = "default";
244 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, expected_weight
,
247 // fail because osd.0 is not a bucket and must not be in loc, in
248 // addition to being of the wrong type
251 map
<string
,string
> loc
;
252 loc
["root"] = "osd.0";
253 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
255 // succeed and retrieves the expected weight
258 map
<string
,string
> loc
;
259 loc
["root"] = "default";
260 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
261 EXPECT_EQ(expected_weight
, weight
);
267 TEST(CrushWrapper
, update_item
) {
268 CrushWrapper
*c
= new CrushWrapper
;
270 const int ROOT_TYPE
= 2;
271 c
->set_type_name(ROOT_TYPE
, "root");
272 const int HOST_TYPE
= 1;
273 c
->set_type_name(HOST_TYPE
, "host");
274 const int OSD_TYPE
= 0;
275 c
->set_type_name(OSD_TYPE
, "osd");
278 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
279 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
280 c
->set_item_name(rootno
, "default");
282 const string
HOST0("host0");
284 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
285 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
286 c
->set_item_name(host0
, HOST0
);
288 const string
HOST1("host1");
290 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
291 HOST_TYPE
, 0, NULL
, NULL
, &host1
);
292 c
->set_item_name(host1
, HOST1
);
296 // fail if invalid names anywhere in loc
298 map
<string
,string
> loc
;
299 loc
["rack"] = "\001";
300 EXPECT_EQ(-EINVAL
, c
->update_item(g_ceph_context
, item
, 1.0,
301 "osd." + stringify(item
), loc
));
303 // fail if invalid item name
305 map
<string
,string
> loc
;
306 EXPECT_EQ(-EINVAL
, c
->update_item(g_ceph_context
, item
, 1.0,
309 const string
OSD0("osd.0");
310 const string
OSD1("osd.1");
311 float original_weight
= 1.0;
312 float modified_weight
= 2.0;
315 map
<string
,string
> loc
;
316 loc
["root"] = "default";
318 EXPECT_GE(0.0, c
->get_item_weightf(host0
));
319 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, original_weight
,
322 // updating nothing changes nothing
323 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
324 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
325 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
326 EXPECT_EQ(0, c
->update_item(g_ceph_context
, item
, original_weight
,
328 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
329 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
330 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
332 // update the name and weight of the item but not the location
333 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
334 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
335 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
336 EXPECT_EQ(1, c
->update_item(g_ceph_context
, item
, modified_weight
,
338 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
339 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
340 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
341 c
->set_item_name(item
, OSD0
);
342 c
->adjust_item_weightf(g_ceph_context
, item
, original_weight
);
344 // update the name and weight of the item and change its location
345 map
<string
,string
> other_loc
;
346 other_loc
["root"] = "default";
347 other_loc
["host"] = HOST1
;
349 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
350 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
351 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
352 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, other_loc
, &weight
));
353 EXPECT_EQ(1, c
->update_item(g_ceph_context
, item
, modified_weight
,
355 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
356 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
357 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
358 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, other_loc
, &weight
));
363 TEST(CrushWrapper
, adjust_item_weight
) {
364 CrushWrapper
*c
= new CrushWrapper
;
366 const int ROOT_TYPE
= 2;
367 c
->set_type_name(ROOT_TYPE
, "root");
368 const int HOST_TYPE
= 1;
369 c
->set_type_name(HOST_TYPE
, "host");
370 const int OSD_TYPE
= 0;
371 c
->set_type_name(OSD_TYPE
, "osd");
374 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
375 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
376 c
->set_item_name(rootno
, "default");
378 const string
HOST0("host0");
380 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
381 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
382 c
->set_item_name(host0
, HOST0
);
384 const string
FAKE("fake");
386 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
387 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
388 c
->set_item_name(hostfake
, FAKE
);
392 // construct crush map
395 map
<string
,string
> loc
;
396 loc
["host"] = "host0";
397 float host_weight
= 2.0;
401 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
402 "osd." + stringify(item
), loc
));
404 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
405 "osd." + stringify(item
), loc
));
407 bucket_id
= c
->get_item_id("host0");
408 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
409 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
411 map
<string
,string
> bloc
;
412 bloc
["root"] = "default";
413 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, host0
, host_weight
,
418 map
<string
,string
> loc
;
419 loc
["host"] = "fake";
420 float host_weight
= 2.0;
424 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
425 "osd." + stringify(item
), loc
));
427 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
428 "osd." + stringify(item
), loc
));
430 bucket_id
= c
->get_item_id("fake");
431 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
432 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
434 map
<string
,string
> bloc
;
435 bloc
["root"] = "default";
436 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, hostfake
, host_weight
,
443 // default --> host0 --> osd.0 1.0
447 // +-> fake --> osd.0 1.0
451 // Trying to adjust osd.0 weight to 2.0 in all buckets
452 // Trying to adjust osd.1 weight to 2.0 in host=fake
454 // So the crush map will be:
456 // default --> host0 --> osd.0 2.0
460 // +-> fake --> osd.0 2.0
465 float original_weight
= 1.0;
466 float modified_weight
= 2.0;
467 map
<string
,string
> loc_one
, loc_two
;
468 loc_one
["host"] = "host0";
469 loc_two
["host"] = "fake";
472 EXPECT_EQ(2, c
->adjust_item_weightf(g_ceph_context
, item
, modified_weight
));
473 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
474 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
477 EXPECT_EQ(1, c
->adjust_item_weightf_in_loc(g_ceph_context
, item
, modified_weight
, loc_two
));
478 EXPECT_EQ(original_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
479 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
484 TEST(CrushWrapper
, adjust_subtree_weight
) {
485 CrushWrapper
*c
= new CrushWrapper
;
487 const int ROOT_TYPE
= 2;
488 c
->set_type_name(ROOT_TYPE
, "root");
489 const int HOST_TYPE
= 1;
490 c
->set_type_name(HOST_TYPE
, "host");
491 const int OSD_TYPE
= 0;
492 c
->set_type_name(OSD_TYPE
, "osd");
495 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
496 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
497 c
->set_item_name(rootno
, "default");
499 const string
HOST0("host0");
501 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
502 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
503 c
->set_item_name(host0
, HOST0
);
505 const string
FAKE("fake");
507 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
508 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
509 c
->set_item_name(hostfake
, FAKE
);
513 // construct crush map
516 map
<string
,string
> loc
;
517 loc
["host"] = "host0";
518 float host_weight
= 2.0;
522 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
523 "osd." + stringify(item
), loc
));
525 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
526 "osd." + stringify(item
), loc
));
528 bucket_id
= c
->get_item_id("host0");
529 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
530 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
532 map
<string
,string
> bloc
;
533 bloc
["root"] = "default";
534 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, host0
, host_weight
,
539 map
<string
,string
> loc
;
540 loc
["host"] = "fake";
541 float host_weight
= 2.0;
545 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
546 "osd." + stringify(item
), loc
));
548 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
549 "osd." + stringify(item
), loc
));
551 bucket_id
= c
->get_item_id("fake");
552 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
553 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
555 map
<string
,string
> bloc
;
556 bloc
["root"] = "default";
557 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, hostfake
, host_weight
,
561 //cout << "--------before---------" << std::endl;
562 //c->dump_tree(&cout, NULL);
563 ASSERT_EQ(c
->get_bucket_weight(host0
), 131072);
564 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144);
566 int r
= c
->adjust_subtree_weightf(g_ceph_context
, host0
, 2.0);
567 ASSERT_EQ(r
, 2); // 2 items changed
569 //cout << "--------after---------" << std::endl;
570 //c->dump_tree(&cout, NULL);
572 ASSERT_EQ(c
->get_bucket_weight(host0
), 262144);
573 ASSERT_EQ(c
->get_item_weight(host0
), 262144);
574 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144 + 131072);
579 TEST(CrushWrapper
, insert_item
) {
580 CrushWrapper
*c
= new CrushWrapper
;
582 const int ROOT_TYPE
= 2;
583 c
->set_type_name(ROOT_TYPE
, "root");
584 const int HOST_TYPE
= 1;
585 c
->set_type_name(HOST_TYPE
, "host");
586 const int OSD_TYPE
= 0;
587 c
->set_type_name(OSD_TYPE
, "osd");
590 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
591 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
592 c
->set_item_name(rootno
, "default");
596 // invalid names anywhere in loc trigger an error
598 map
<string
,string
> loc
;
599 loc
["host"] = "\001";
600 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
601 "osd." + stringify(item
), loc
));
604 // insert an item in an existing bucket
606 map
<string
,string
> loc
;
607 loc
["root"] = "default";
610 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
611 "osd." + stringify(item
), loc
));
612 int another_item
= item
+ 1;
613 EXPECT_EQ(-EEXIST
, c
->insert_item(g_ceph_context
, another_item
, 1.0,
614 "osd." + stringify(item
), loc
));
616 // implicit creation of a bucket
618 string name
= "NAME";
619 map
<string
,string
> loc
;
620 loc
["root"] = "default";
624 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
625 "osd." + stringify(item
), loc
));
627 // adding to an existing item name that is not associated with a bucket
629 string name
= "ITEM_WITHOUT_BUCKET";
630 map
<string
,string
> loc
;
631 loc
["root"] = "default";
634 c
->set_item_name(item
, name
);
637 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
638 "osd." + stringify(item
), loc
));
643 // default --> host0 --> item
645 // Trying to insert the same item higher in the hirarchy will fail
646 // because it would create a loop.
648 // default --> host0 --> item
655 map
<string
,string
> loc
;
656 loc
["root"] = "default";
657 loc
["host"] = "host0";
659 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
660 "osd." + stringify(item
), loc
));
663 map
<string
,string
> loc
;
664 loc
["root"] = "default";
666 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
667 "osd." + stringify(item
), loc
));
675 // Trying to insert default under host0 must fail
676 // because it would create a loop.
678 // default --> host0 --> default
681 map
<string
,string
> loc
;
682 loc
["host"] = "host0";
684 EXPECT_EQ(-ELOOP
, c
->insert_item(g_ceph_context
, rootno
, 1.0,
687 // fail when mapping a bucket to the wrong type
689 // create an OSD bucket
691 int r
= c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
692 10, 0, NULL
, NULL
, &osdno
);
694 c
->set_item_name(osdno
, "myosd");
695 map
<string
,string
> loc
;
696 loc
["root"] = "default";
697 // wrongfully pretend the osd is of type host
698 loc
["host"] = "myosd";
701 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
702 "osd." + stringify(item
), loc
));
704 // fail when no location
706 map
<string
,string
> loc
;
708 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
709 "osd." + stringify(item
), loc
));
715 TEST(CrushWrapper
, choose_args_disabled
) {
716 auto *c
= new CrushWrapper
;
717 c
->choose_args
[0] = crush_choose_arg_map();
719 map
<string
,string
> loc
;
720 ASSERT_EQ(-EDOM
, c
->remove_item(g_ceph_context
, 0, true));
721 ASSERT_EQ(-EDOM
, c
->insert_item(g_ceph_context
, 0, 0.0, "", loc
));
722 ASSERT_EQ(-EDOM
, c
->move_bucket(g_ceph_context
, 0, loc
));
723 ASSERT_EQ(-EDOM
, c
->link_bucket(g_ceph_context
, 0, loc
));
724 ASSERT_EQ(-EDOM
, c
->create_or_move_item(g_ceph_context
, 0, 0.0, "", loc
));
729 TEST(CrushWrapper
, remove_item
) {
730 auto *c
= new CrushWrapper
;
732 const int ROOT_TYPE
= 2;
733 c
->set_type_name(ROOT_TYPE
, "root");
734 const int HOST_TYPE
= 1;
735 c
->set_type_name(HOST_TYPE
, "host");
736 const int OSD_TYPE
= 0;
737 c
->set_type_name(OSD_TYPE
, "osd");
741 ASSERT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
742 ROOT_TYPE
, 0, NULL
, NULL
, &root
));
743 c
->set_item_name(root
, "root0");
748 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
749 HOST_TYPE
, 0, NULL
, NULL
, &host
);
750 c
->set_item_name(host
, "host0");
753 const int num_osd
= 12;
755 map
<string
, string
> loc
= {{"root", "root0"},
758 for (int item
= 0; item
< num_osd
; item
++) {
759 ASSERT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
760 name
+ to_string(item
), loc
));
763 const int item_to_remove
= num_osd
/ 2;
764 map
<string
, string
> loc
;
765 loc
.insert(c
->get_immediate_parent(item_to_remove
));
766 ASSERT_EQ(0, c
->remove_item(g_ceph_context
, item_to_remove
, true));
768 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item_to_remove
, loc
, &weight
));
773 TEST(CrushWrapper
, item_bucket_names
) {
774 CrushWrapper
*c
= new CrushWrapper
;
776 string name
= "NAME";
777 EXPECT_EQ(-EINVAL
, c
->set_item_name(index
, "\001"));
778 EXPECT_EQ(0, c
->set_item_name(index
, name
));
779 EXPECT_TRUE(c
->name_exists(name
));
780 EXPECT_TRUE(c
->item_exists(index
));
781 EXPECT_EQ(index
, c
->get_item_id(name
));
782 EXPECT_EQ(name
, c
->get_item_name(index
));
786 TEST(CrushWrapper
, bucket_types
) {
787 CrushWrapper
*c
= new CrushWrapper
;
789 string name
= "NAME";
790 c
->set_type_name(index
, name
);
791 EXPECT_EQ(1, c
->get_num_type_names());
792 EXPECT_EQ(index
, c
->get_type_id(name
));
793 EXPECT_EQ(name
, c
->get_type_name(index
));
797 TEST(CrushWrapper
, is_valid_crush_name
) {
798 EXPECT_TRUE(CrushWrapper::is_valid_crush_name("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012456789-_"));
799 EXPECT_FALSE(CrushWrapper::is_valid_crush_name(""));
800 EXPECT_FALSE(CrushWrapper::is_valid_crush_name("\001"));
803 TEST(CrushWrapper
, is_valid_crush_loc
) {
804 map
<string
,string
> loc
;
805 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
806 loc
["good"] = "better";
807 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
809 map
<string
,string
> loc
;
810 loc
["\005"] = "default";
811 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
814 map
<string
,string
> loc
;
815 loc
["host"] = "\003";
816 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
820 TEST(CrushWrapper
, dump_rules
) {
821 CrushWrapper
*c
= new CrushWrapper
;
823 const int ROOT_TYPE
= 1;
824 c
->set_type_name(ROOT_TYPE
, "root");
825 const int OSD_TYPE
= 0;
826 c
->set_type_name(OSD_TYPE
, "osd");
828 string
failure_domain_type("osd");
829 string
root_name("default");
831 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
832 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
833 c
->set_item_name(rootno
, root_name
);
837 pair
<string
,string
> loc
;
839 loc
= c
->get_immediate_parent(item
, &ret
);
840 EXPECT_EQ(-ENOENT
, ret
);
843 map
<string
,string
> loc
;
844 loc
["root"] = root_name
;
846 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
850 // no ruleset by default
852 Formatter
*f
= Formatter::create("json-pretty");
853 f
->open_array_section("rules");
859 EXPECT_EQ("[]\n", ss
.str());
863 int ruleset
= c
->add_simple_ruleset(name
, root_name
, failure_domain_type
,
864 "firstn", pg_pool_t::TYPE_ERASURE
);
865 EXPECT_EQ(0, ruleset
);
868 Formatter
*f
= Formatter::create("xml");
873 EXPECT_EQ((unsigned)0, ss
.str().find("<rule><rule_id>0</rule_id><rule_name>NAME</rule_name>"));
877 Formatter
*f
= Formatter::create("xml");
878 c
->dump_rule(ruleset
, f
);
882 EXPECT_EQ((unsigned)0, ss
.str().find("<rule><rule_id>0</rule_id><rule_name>NAME</rule_name>"));
883 EXPECT_NE(string::npos
,
884 ss
.str().find("<item_name>default</item_name></step>"));
888 c
->get_rule_weight_osd_map(0, &wm
);
889 ASSERT_TRUE(wm
.size() == 1);
890 ASSERT_TRUE(wm
[0] == 1.0);
895 TEST(CrushWrapper
, distance
) {
898 c
.set_type_name(1, "host");
899 c
.set_type_name(2, "rack");
900 c
.set_type_name(3, "root");
902 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW
,
903 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
907 c
.set_item_name(bno
, "default");
909 c
.set_max_devices(10);
911 //JSONFormatter jf(true);
913 map
<string
,string
> loc
;
916 loc
["root"] = "default";
917 c
.insert_item(g_ceph_context
, 0, 1, "osd.0", loc
);
922 loc
["root"] = "default";
923 c
.insert_item(g_ceph_context
, 1, 1, "osd.1", loc
);
928 loc
["root"] = "default";
929 c
.insert_item(g_ceph_context
, 2, 1, "osd.2", loc
);
934 loc
["root"] = "default";
935 c
.insert_item(g_ceph_context
, 3, 1, "osd.3", loc
);
937 vector
<pair
<string
,string
> > ol
;
938 c
.get_full_location_ordered(3, ol
);
939 ASSERT_EQ(3u, ol
.size());
940 ASSERT_EQ(make_pair(string("host"),string("b2")), ol
[0]);
941 ASSERT_EQ(make_pair(string("rack"),string("b")), ol
[1]);
942 ASSERT_EQ(make_pair(string("root"),string("default")), ol
[2]);
947 multimap
<string
,string
> p
;
948 p
.insert(make_pair("host","b2"));
949 p
.insert(make_pair("rack","b"));
950 p
.insert(make_pair("root","default"));
951 ASSERT_EQ(3, c
.get_common_ancestor_distance(g_ceph_context
, 0, p
));
952 ASSERT_EQ(3, c
.get_common_ancestor_distance(g_ceph_context
, 1, p
));
953 ASSERT_EQ(2, c
.get_common_ancestor_distance(g_ceph_context
, 2, p
));
954 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 3, p
));
955 ASSERT_EQ(-ENOENT
, c
.get_common_ancestor_distance(g_ceph_context
, 123, p
));
957 // make sure a "multipath" location will reflect a minimal
958 // distance for both paths
959 p
.insert(make_pair("host","b1"));
960 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 2, p
));
961 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 3, p
));
964 TEST(CrushWrapper
, remove_unused_root
) {
967 c
.set_type_name(1, "host");
968 c
.set_type_name(2, "rack");
969 c
.set_type_name(3, "root");
973 map
<string
,string
> loc
;
976 loc
["root"] = "default";
978 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
982 loc
["root"] = "default";
983 c
.insert_item(g_ceph_context
, item
, weight
, "osd.2", loc
);
985 assert(c
.add_simple_ruleset("rule1", "r11", "host", "firstn", pg_pool_t::TYPE_ERASURE
) >= 0);
986 ASSERT_TRUE(c
.name_exists("default"));
987 ASSERT_TRUE(c
.name_exists("r11"));
988 ASSERT_TRUE(c
.name_exists("r12"));
989 ASSERT_EQ(c
.remove_root(c
.get_item_id("default"), true), 0);
990 ASSERT_FALSE(c
.name_exists("default"));
991 ASSERT_TRUE(c
.name_exists("r11"));
992 ASSERT_FALSE(c
.name_exists("r12"));
995 TEST(CrushWrapper
, trim_roots_with_class
) {
998 c
.set_type_name(1, "root");
1001 map
<string
,string
> loc
;
1002 loc
["root"] = "default";
1005 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1006 int cl
= c
.get_or_create_class_id("ssd");
1007 c
.class_map
[item
] = cl
;
1010 int root_id
= c
.get_item_id("default");
1012 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, &clone_id
), 0);
1014 ASSERT_TRUE(c
.name_exists("default"));
1015 ASSERT_TRUE(c
.name_exists("default~ssd"));
1016 c
.trim_roots_with_class(true); // do nothing because still in use
1017 ASSERT_TRUE(c
.name_exists("default"));
1018 ASSERT_TRUE(c
.name_exists("default~ssd"));
1019 c
.class_bucket
.clear();
1020 c
.trim_roots_with_class(true); // do nothing because still in use
1021 ASSERT_TRUE(c
.name_exists("default"));
1022 ASSERT_FALSE(c
.name_exists("default~ssd"));
1025 TEST(CrushWrapper
, device_class_clone
) {
1028 c
.set_type_name(1, "host");
1029 c
.set_type_name(2, "root");
1031 map
<string
,string
> loc
;
1033 loc
["root"] = "default";
1037 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1038 int cl
= c
.get_or_create_class_id("ssd");
1039 c
.class_map
[item
] = cl
;
1041 int item_no_class
= 2;
1042 c
.insert_item(g_ceph_context
, item_no_class
, weight
, "osd.2", loc
);
1044 c
.reweight(g_ceph_context
);
1046 int root_id
= c
.get_item_id("default");
1048 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, &clone_id
), 0);
1049 ASSERT_TRUE(c
.name_exists("default~ssd"));
1050 ASSERT_EQ(clone_id
, c
.get_item_id("default~ssd"));
1051 ASSERT_TRUE(c
.subtree_contains(clone_id
, item
));
1052 ASSERT_FALSE(c
.subtree_contains(clone_id
, item_no_class
));
1053 ASSERT_TRUE(c
.subtree_contains(root_id
, item_no_class
));
1054 ASSERT_EQ(c
.get_item_weightf(root_id
), 2);
1055 ASSERT_EQ(c
.get_item_weightf(clone_id
), 1);
1056 // cloning again does nothing and returns the existing one
1058 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, &other_clone_id
), 0);
1059 ASSERT_EQ(clone_id
, other_clone_id
);
1060 // invalid arguments
1061 ASSERT_EQ(c
.device_class_clone(12345, cl
, &other_clone_id
), -ECHILD
);
1062 ASSERT_EQ(c
.device_class_clone(root_id
, 12345, &other_clone_id
), -EBADF
);
1065 TEST(CrushWrapper
, split_id_class
) {
1068 c
.set_type_name(1, "root");
1071 map
<string
,string
> loc
;
1072 loc
["root"] = "default";
1075 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1076 int class_id
= c
.get_or_create_class_id("ssd");
1077 c
.class_map
[item
] = class_id
;
1079 int item_id
= c
.get_item_id("default");
1081 ASSERT_EQ(c
.device_class_clone(item_id
, class_id
, &clone_id
), 0);
1082 int retrieved_item_id
;
1083 int retrieved_class_id
;
1084 ASSERT_EQ(c
.split_id_class(clone_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1085 ASSERT_EQ(item_id
, retrieved_item_id
);
1086 ASSERT_EQ(class_id
, retrieved_class_id
);
1088 ASSERT_EQ(c
.split_id_class(item_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1089 ASSERT_EQ(item_id
, retrieved_item_id
);
1090 ASSERT_EQ(-1, retrieved_class_id
);
1093 TEST(CrushWrapper
, populate_and_cleanup_classes
) {
1096 c
.set_type_name(1, "root");
1099 map
<string
,string
> loc
;
1100 loc
["root"] = "default";
1103 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1104 int class_id
= c
.get_or_create_class_id("ssd");
1105 c
.class_map
[item
] = class_id
;
1107 ASSERT_EQ(c
.populate_classes(), 0);
1109 ASSERT_TRUE(c
.name_exists("default~ssd"));
1111 c
.class_bucket
.clear();
1112 ASSERT_EQ(c
.cleanup_classes(), 0);
1113 ASSERT_FALSE(c
.name_exists("default~ssd"));
1116 TEST(CrushWrapper
, class_is_in_use
) {
1119 c
.set_type_name(1, "root");
1122 map
<string
,string
> loc
;
1123 loc
["root"] = "default";
1125 ASSERT_FALSE(c
.class_is_in_use(0));
1128 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1129 int class_id
= c
.get_or_create_class_id("ssd");
1130 c
.class_map
[item
] = class_id
;
1132 ASSERT_TRUE(c
.class_is_in_use(c
.get_class_id("ssd")));
1133 ASSERT_EQ(0, c
.remove_class_name("ssd"));
1134 ASSERT_FALSE(c
.class_is_in_use(c
.get_class_id("ssd")));
1137 TEST(CrushWrapper
, remove_class_name
) {
1141 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1142 ASSERT_GE(0, c
.get_or_create_class_id("ssd"));
1143 ASSERT_EQ(0, c
.remove_class_name("ssd"));
1144 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1147 TEST(CrushWrapper
, try_remap_rule
) {
1148 // build a simple 2 level map
1151 c
.set_type_name(0, "osd");
1152 c
.set_type_name(1, "host");
1153 c
.set_type_name(2, "rack");
1154 c
.set_type_name(3, "root");
1156 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW2
,
1157 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
1161 c
.set_item_name(bno
, "default");
1163 c
.set_max_devices(20);
1165 //JSONFormatter jf(true);
1167 map
<string
,string
> loc
;
1168 loc
["host"] = "foo";
1170 loc
["root"] = "default";
1171 c
.insert_item(g_ceph_context
, 0, 1, "osd.0", loc
);
1172 c
.insert_item(g_ceph_context
, 1, 1, "osd.1", loc
);
1173 c
.insert_item(g_ceph_context
, 2, 1, "osd.2", loc
);
1176 loc
["host"] = "bar";
1178 loc
["root"] = "default";
1179 c
.insert_item(g_ceph_context
, 3, 1, "osd.3", loc
);
1180 c
.insert_item(g_ceph_context
, 4, 1, "osd.4", loc
);
1181 c
.insert_item(g_ceph_context
, 5, 1, "osd.5", loc
);
1184 loc
["host"] = "baz";
1186 loc
["root"] = "default";
1187 c
.insert_item(g_ceph_context
, 6, 1, "osd.6", loc
);
1188 c
.insert_item(g_ceph_context
, 7, 1, "osd.7", loc
);
1189 c
.insert_item(g_ceph_context
, 8, 1, "osd.8", loc
);
1192 loc
["host"] = "qux";
1194 loc
["root"] = "default";
1195 c
.insert_item(g_ceph_context
, 9, 1, "osd.9", loc
);
1196 c
.insert_item(g_ceph_context
, 10, 1, "osd.10", loc
);
1197 c
.insert_item(g_ceph_context
, 11, 1, "osd.11", loc
);
1201 loc
["host"] = "bif";
1203 loc
["root"] = "default";
1204 c
.insert_item(g_ceph_context
, 12, 1, "osd.12", loc
);
1205 c
.insert_item(g_ceph_context
, 13, 1, "osd.13", loc
);
1206 c
.insert_item(g_ceph_context
, 14, 1, "osd.14", loc
);
1210 loc
["host"] = "pop";
1212 loc
["root"] = "default";
1213 c
.insert_item(g_ceph_context
, 15, 1, "osd.15", loc
);
1214 c
.insert_item(g_ceph_context
, 16, 1, "osd.16", loc
);
1215 c
.insert_item(g_ceph_context
, 17, 1, "osd.17", loc
);
1225 // take + choose device + emit
1227 cout
<< "take + choose + emit" << std::endl
;
1229 int rule
= c
.add_simple_ruleset("one", "default", "osd", "firstn", 0, &err
);
1232 vector
<int> orig
= { 0, 3, 9 };
1233 set
<int> overfull
= { 3 };
1234 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1236 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1237 overfull
, underfull
,
1239 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1241 ASSERT_EQ(3u, out
.size());
1242 ASSERT_EQ(0, out
[0]);
1243 ASSERT_EQ(2, out
[1]);
1244 ASSERT_EQ(9, out
[2]);
1246 // make sure we cope with dups between underfull and future values in orig
1247 underfull
= {9, 0, 2, 5};
1250 r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1251 overfull
, underfull
,
1253 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1255 ASSERT_EQ(3u, out
.size());
1256 ASSERT_EQ(1, out
[0]);
1257 ASSERT_EQ(0, out
[1]);
1258 ASSERT_EQ(9, out
[2]);
1263 cout
<< "take + chooseleaf + emit" << std::endl
;
1265 int rule
= c
.add_simple_ruleset("two", "default", "host", "firstn", 0, &err
);
1268 vector
<int> orig
= { 0, 3, 9 };
1269 set
<int> overfull
= { 3 };
1270 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1272 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1273 overfull
, underfull
,
1275 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1277 ASSERT_EQ(3u, out
.size());
1278 ASSERT_EQ(0, out
[0]);
1279 ASSERT_EQ(5, out
[1]);
1280 ASSERT_EQ(9, out
[2]);
1285 cout
<< "take + choose + choose + choose + emit" << std::endl
;
1286 int rule
= c
.add_rule(5, 2, 0, 1, 10, 2);
1288 c
.set_rule_step_take(rule
, 0, bno
);
1289 c
.set_rule_step_choose_indep(rule
, 1, 2, 2);
1290 c
.set_rule_step_choose_indep(rule
, 2, 2, 1);
1291 c
.set_rule_step_choose_indep(rule
, 3, 1, 0);
1292 c
.set_rule_step_emit(rule
, 4);
1294 vector
<int> orig
= { 0, 3, 16, 12 };
1295 set
<int> overfull
= { 3, 12 };
1296 vector
<int> underfull
= { 6, 7, 9, 3, 0, 1, 15, 16, 13, 2, 5, 8, 11 };
1298 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1299 overfull
, underfull
,
1301 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1303 ASSERT_EQ(4u, out
.size());
1304 ASSERT_EQ(0, out
[0]);
1305 ASSERT_EQ(5, out
[1]);
1306 ASSERT_EQ(16, out
[2]);
1307 ASSERT_EQ(13, out
[3]);
1311 r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1312 overfull
, underfull
,
1314 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1316 ASSERT_EQ(3u, out
.size());
1317 ASSERT_EQ(0, out
[0]);
1318 ASSERT_EQ(5, out
[1]);
1319 ASSERT_EQ(16, out
[2]);
1323 int main(int argc
, char **argv
) {
1324 vector
<const char*> args
;
1325 argv_to_vec(argc
, (const char **)argv
, args
);
1328 vector
<const char*> def_args
;
1329 def_args
.push_back("--debug-crush=0");
1330 auto cct
= global_init(&def_args
, args
, CEPH_ENTITY_TYPE_CLIENT
,
1331 CODE_ENVIRONMENT_UTILITY
, 0);
1332 common_init_finish(g_ceph_context
);
1333 ::testing::InitGoogleTest(&argc
, argv
);
1334 return RUN_ALL_TESTS();
1337 // compile-command: "cd ../../../build ; make -j4 unittest_crush_wrapper && valgrind --tool=memcheck bin/unittest_crush_wrapper"