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
, swap_bucket
) {
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_STRAW2
, CRUSH_HASH_RJENKINS1
,
143 ROOT_TYPE
, 0, NULL
, NULL
, &root
));
144 EXPECT_EQ(0, c
->set_item_name(root
, "root"));
147 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
148 HOST_TYPE
, 0, NULL
, NULL
, &a
));
149 EXPECT_EQ(0, c
->set_item_name(a
, "a"));
150 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
151 HOST_TYPE
, 0, NULL
, NULL
, &b
));
152 EXPECT_EQ(0, c
->set_item_name(b
, "b"));
155 map
<string
,string
> loc
;
156 loc
["root"] = "root";
157 EXPECT_EQ(0, c
->move_bucket(g_ceph_context
, a
, loc
));
160 map
<string
,string
> loc
;
161 loc
["root"] = "root";
163 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 0, 1.0, "osd.0", loc
));
164 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 1, 1.0, "osd.1", loc
));
165 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 2, 1.0, "osd.2", loc
));
168 map
<string
,string
> loc
;
170 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 3, 1.0, "osd.3", loc
));
172 ASSERT_EQ(0x30000, c
->get_item_weight(a
));
173 ASSERT_EQ(string("a"), c
->get_item_name(a
));
174 ASSERT_EQ(0x10000, c
->get_item_weight(b
));
175 ASSERT_EQ(string("b"), c
->get_item_name(b
));
176 ASSERT_EQ(a
, c
->get_bucket_item(root
, 0));
177 ASSERT_EQ(0, c
->get_bucket_item(a
, 0));
178 ASSERT_EQ(1, c
->get_bucket_item(a
, 1));
179 ASSERT_EQ(2, c
->get_bucket_item(a
, 2));
180 ASSERT_EQ(3, c
->get_bucket_item(b
, 0));
182 c
->swap_bucket(g_ceph_context
, a
, b
);
183 ASSERT_EQ(0x30000, c
->get_item_weight(b
));
184 ASSERT_EQ(string("a"), c
->get_item_name(b
));
185 ASSERT_EQ(0x10000, c
->get_item_weight(a
));
186 ASSERT_EQ(string("b"), c
->get_item_name(a
));
187 ASSERT_EQ(a
, c
->get_bucket_item(root
, 0));
188 ASSERT_EQ(0, c
->get_bucket_item(b
, 0));
189 ASSERT_EQ(1, c
->get_bucket_item(b
, 1));
190 ASSERT_EQ(2, c
->get_bucket_item(b
, 2));
191 ASSERT_EQ(3, c
->get_bucket_item(a
, 0));
194 TEST(CrushWrapper
, rename_bucket_or_item
) {
195 CrushWrapper
*c
= new CrushWrapper
;
197 const int ROOT_TYPE
= 2;
198 c
->set_type_name(ROOT_TYPE
, "root");
199 const int HOST_TYPE
= 1;
200 c
->set_type_name(HOST_TYPE
, "host");
201 const int OSD_TYPE
= 0;
202 c
->set_type_name(OSD_TYPE
, "osd");
205 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
206 ROOT_TYPE
, 0, NULL
, NULL
, &root0
));
207 EXPECT_EQ(0, c
->set_item_name(root0
, "root0"));
211 map
<string
,string
> loc
;
212 loc
["root"] = "root0";
213 loc
["host"] = "host0";
215 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
220 map
<string
,string
> loc
;
221 loc
["root"] = "root0";
222 loc
["host"] = "host1";
224 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
229 EXPECT_EQ(-EINVAL
, c
->can_rename_item("host0", "????", &ss
));
230 EXPECT_EQ(-EINVAL
, c
->rename_item("host0", "????", &ss
));
231 EXPECT_EQ(-EINVAL
, c
->can_rename_bucket("host0", "????", &ss
));
232 EXPECT_EQ(-EINVAL
, c
->rename_bucket("host0", "????", &ss
));
234 EXPECT_EQ(-EEXIST
, c
->can_rename_item("host0", "host1", &ss
));
235 EXPECT_EQ(-EEXIST
, c
->rename_item("host0", "host1", &ss
));
236 EXPECT_EQ(-EEXIST
, c
->can_rename_bucket("host0", "host1", &ss
));
237 EXPECT_EQ(-EEXIST
, c
->rename_bucket("host0", "host1", &ss
));
239 EXPECT_EQ(-EALREADY
, c
->can_rename_item("gone", "host1", &ss
));
240 EXPECT_EQ(-EALREADY
, c
->rename_item("gone", "host1", &ss
));
241 EXPECT_EQ(-EALREADY
, c
->can_rename_bucket("gone", "host1", &ss
));
242 EXPECT_EQ(-EALREADY
, c
->rename_bucket("gone", "host1", &ss
));
244 EXPECT_EQ(-ENOENT
, c
->can_rename_item("doesnotexist", "somethingelse", &ss
));
245 EXPECT_EQ(-ENOENT
, c
->rename_item("doesnotexist", "somethingelse", &ss
));
246 EXPECT_EQ(-ENOENT
, c
->can_rename_bucket("doesnotexist", "somethingelse", &ss
));
247 EXPECT_EQ(-ENOENT
, c
->rename_bucket("doesnotexist", "somethingelse", &ss
));
249 EXPECT_EQ(-ENOTDIR
, c
->can_rename_bucket("osd.1", "somethingelse", &ss
));
250 EXPECT_EQ(-ENOTDIR
, c
->rename_bucket("osd.1", "somethingelse", &ss
));
252 int host0id
= c
->get_item_id("host0");
253 EXPECT_EQ(0, c
->rename_bucket("host0", "host0renamed", &ss
));
254 EXPECT_EQ(host0id
, c
->get_item_id("host0renamed"));
256 int osd0id
= c
->get_item_id("osd0");
257 EXPECT_EQ(0, c
->rename_item("osd.0", "osd0renamed", &ss
));
258 EXPECT_EQ(osd0id
, c
->get_item_id("osd0renamed"));
263 TEST(CrushWrapper
, check_item_loc
) {
264 CrushWrapper
*c
= new CrushWrapper
;
266 float expected_weight
= 1.0;
268 // fail if loc is empty
271 map
<string
,string
> loc
;
272 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
275 const int ROOT_TYPE
= 2;
276 c
->set_type_name(ROOT_TYPE
, "root");
277 const int HOST_TYPE
= 1;
278 c
->set_type_name(HOST_TYPE
, "host");
279 const int OSD_TYPE
= 0;
280 c
->set_type_name(OSD_TYPE
, "osd");
283 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
284 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
285 c
->set_item_name(rootno
, "default");
287 // fail because the item is not found at the specified location
290 map
<string
,string
> loc
;
291 loc
["root"] = "default";
292 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
294 // fail because the bucket name does not match an existing bucket
297 map
<string
,string
> loc
;
298 loc
["root"] = "default";
299 const string
HOST("host0");
301 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
303 const string
OSD("osd.0");
305 map
<string
,string
> loc
;
306 loc
["root"] = "default";
307 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, expected_weight
,
310 // fail because osd.0 is not a bucket and must not be in loc, in
311 // addition to being of the wrong type
314 map
<string
,string
> loc
;
315 loc
["root"] = "osd.0";
316 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
318 // succeed and retrieves the expected weight
321 map
<string
,string
> loc
;
322 loc
["root"] = "default";
323 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
324 EXPECT_EQ(expected_weight
, weight
);
330 TEST(CrushWrapper
, update_item
) {
331 CrushWrapper
*c
= new CrushWrapper
;
333 const int ROOT_TYPE
= 2;
334 c
->set_type_name(ROOT_TYPE
, "root");
335 const int HOST_TYPE
= 1;
336 c
->set_type_name(HOST_TYPE
, "host");
337 const int OSD_TYPE
= 0;
338 c
->set_type_name(OSD_TYPE
, "osd");
341 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
342 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
343 c
->set_item_name(rootno
, "default");
345 const string
HOST0("host0");
347 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
348 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
349 c
->set_item_name(host0
, HOST0
);
351 const string
HOST1("host1");
353 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
354 HOST_TYPE
, 0, NULL
, NULL
, &host1
);
355 c
->set_item_name(host1
, HOST1
);
359 // fail if invalid names anywhere in loc
361 map
<string
,string
> loc
;
362 loc
["rack"] = "\001";
363 EXPECT_EQ(-EINVAL
, c
->update_item(g_ceph_context
, item
, 1.0,
364 "osd." + stringify(item
), loc
));
366 // fail if invalid item name
368 map
<string
,string
> loc
;
369 EXPECT_EQ(-EINVAL
, c
->update_item(g_ceph_context
, item
, 1.0,
372 const string
OSD0("osd.0");
373 const string
OSD1("osd.1");
374 float original_weight
= 1.0;
375 float modified_weight
= 2.0;
378 map
<string
,string
> loc
;
379 loc
["root"] = "default";
381 EXPECT_GE(0.0, c
->get_item_weightf(host0
));
382 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, original_weight
,
385 // updating nothing changes nothing
386 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
387 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
388 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
389 EXPECT_EQ(0, c
->update_item(g_ceph_context
, item
, original_weight
,
391 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
392 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
393 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
395 // update the name and weight of the item but not the location
396 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
397 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
398 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
399 EXPECT_EQ(1, c
->update_item(g_ceph_context
, item
, modified_weight
,
401 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
402 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
403 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
404 c
->set_item_name(item
, OSD0
);
405 c
->adjust_item_weightf(g_ceph_context
, item
, original_weight
);
407 // update the name and weight of the item and change its location
408 map
<string
,string
> other_loc
;
409 other_loc
["root"] = "default";
410 other_loc
["host"] = HOST1
;
412 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
413 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
414 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
415 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, other_loc
, &weight
));
416 EXPECT_EQ(1, c
->update_item(g_ceph_context
, item
, modified_weight
,
418 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
419 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
420 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
421 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, other_loc
, &weight
));
426 TEST(CrushWrapper
, adjust_item_weight
) {
427 CrushWrapper
*c
= new CrushWrapper
;
429 const int ROOT_TYPE
= 2;
430 c
->set_type_name(ROOT_TYPE
, "root");
431 const int HOST_TYPE
= 1;
432 c
->set_type_name(HOST_TYPE
, "host");
433 const int OSD_TYPE
= 0;
434 c
->set_type_name(OSD_TYPE
, "osd");
437 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
438 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
439 c
->set_item_name(rootno
, "default");
441 const string
HOST0("host0");
443 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
444 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
445 c
->set_item_name(host0
, HOST0
);
447 const string
FAKE("fake");
449 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
450 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
451 c
->set_item_name(hostfake
, FAKE
);
455 // construct crush map
458 map
<string
,string
> loc
;
459 loc
["host"] = "host0";
460 float host_weight
= 2.0;
464 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
465 "osd." + stringify(item
), loc
));
467 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
468 "osd." + stringify(item
), loc
));
470 bucket_id
= c
->get_item_id("host0");
471 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
472 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
474 map
<string
,string
> bloc
;
475 bloc
["root"] = "default";
476 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, host0
, host_weight
,
481 map
<string
,string
> loc
;
482 loc
["host"] = "fake";
483 float host_weight
= 2.0;
487 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
488 "osd." + stringify(item
), loc
));
490 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
491 "osd." + stringify(item
), loc
));
493 bucket_id
= c
->get_item_id("fake");
494 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
495 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
497 map
<string
,string
> bloc
;
498 bloc
["root"] = "default";
499 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, hostfake
, host_weight
,
506 // default --> host0 --> osd.0 1.0
510 // +-> fake --> osd.0 1.0
514 // Trying to adjust osd.0 weight to 2.0 in all buckets
515 // Trying to adjust osd.1 weight to 2.0 in host=fake
517 // So the crush map will be:
519 // default --> host0 --> osd.0 2.0
523 // +-> fake --> osd.0 2.0
528 float original_weight
= 1.0;
529 float modified_weight
= 2.0;
530 map
<string
,string
> loc_one
, loc_two
;
531 loc_one
["host"] = "host0";
532 loc_two
["host"] = "fake";
535 EXPECT_EQ(2, c
->adjust_item_weightf(g_ceph_context
, item
, modified_weight
));
536 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
537 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
540 EXPECT_EQ(1, c
->adjust_item_weightf_in_loc(g_ceph_context
, item
, modified_weight
, loc_two
));
541 EXPECT_EQ(original_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
542 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
547 TEST(CrushWrapper
, adjust_subtree_weight
) {
548 CrushWrapper
*c
= new CrushWrapper
;
550 const int ROOT_TYPE
= 2;
551 c
->set_type_name(ROOT_TYPE
, "root");
552 const int HOST_TYPE
= 1;
553 c
->set_type_name(HOST_TYPE
, "host");
554 const int OSD_TYPE
= 0;
555 c
->set_type_name(OSD_TYPE
, "osd");
558 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
559 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
560 c
->set_item_name(rootno
, "default");
562 const string
HOST0("host0");
564 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
565 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
566 c
->set_item_name(host0
, HOST0
);
568 const string
FAKE("fake");
570 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
571 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
572 c
->set_item_name(hostfake
, FAKE
);
576 // construct crush map
579 map
<string
,string
> loc
;
580 loc
["host"] = "host0";
581 float host_weight
= 2.0;
585 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
586 "osd." + stringify(item
), loc
));
588 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
589 "osd." + stringify(item
), loc
));
591 bucket_id
= c
->get_item_id("host0");
592 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
593 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
595 map
<string
,string
> bloc
;
596 bloc
["root"] = "default";
597 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, host0
, host_weight
,
602 map
<string
,string
> loc
;
603 loc
["host"] = "fake";
604 float host_weight
= 2.0;
608 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
609 "osd." + stringify(item
), loc
));
611 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
612 "osd." + stringify(item
), loc
));
614 bucket_id
= c
->get_item_id("fake");
615 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
616 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
618 map
<string
,string
> bloc
;
619 bloc
["root"] = "default";
620 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, hostfake
, host_weight
,
624 //cout << "--------before---------" << std::endl;
625 //c->dump_tree(&cout, NULL);
626 ASSERT_EQ(c
->get_bucket_weight(host0
), 131072);
627 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144);
629 int r
= c
->adjust_subtree_weightf(g_ceph_context
, host0
, 2.0);
630 ASSERT_EQ(r
, 2); // 2 items changed
632 //cout << "--------after---------" << std::endl;
633 //c->dump_tree(&cout, NULL);
635 ASSERT_EQ(c
->get_bucket_weight(host0
), 262144);
636 ASSERT_EQ(c
->get_item_weight(host0
), 262144);
637 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144 + 131072);
642 TEST(CrushWrapper
, insert_item
) {
643 CrushWrapper
*c
= new CrushWrapper
;
645 const int ROOT_TYPE
= 2;
646 c
->set_type_name(ROOT_TYPE
, "root");
647 const int HOST_TYPE
= 1;
648 c
->set_type_name(HOST_TYPE
, "host");
649 const int OSD_TYPE
= 0;
650 c
->set_type_name(OSD_TYPE
, "osd");
653 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
654 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
655 c
->set_item_name(rootno
, "default");
659 // invalid names anywhere in loc trigger an error
661 map
<string
,string
> loc
;
662 loc
["host"] = "\001";
663 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
664 "osd." + stringify(item
), loc
));
667 // insert an item in an existing bucket
669 map
<string
,string
> loc
;
670 loc
["root"] = "default";
673 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
674 "osd." + stringify(item
), loc
));
675 int another_item
= item
+ 1;
676 EXPECT_EQ(-EEXIST
, c
->insert_item(g_ceph_context
, another_item
, 1.0,
677 "osd." + stringify(item
), loc
));
679 // implicit creation of a bucket
681 string name
= "NAME";
682 map
<string
,string
> loc
;
683 loc
["root"] = "default";
687 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
688 "osd." + stringify(item
), loc
));
690 // adding to an existing item name that is not associated with a bucket
692 string name
= "ITEM_WITHOUT_BUCKET";
693 map
<string
,string
> loc
;
694 loc
["root"] = "default";
697 c
->set_item_name(item
, name
);
700 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
701 "osd." + stringify(item
), loc
));
706 // default --> host0 --> item
708 // Trying to insert the same item higher in the hirarchy will fail
709 // because it would create a loop.
711 // default --> host0 --> item
718 map
<string
,string
> loc
;
719 loc
["root"] = "default";
720 loc
["host"] = "host0";
722 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
723 "osd." + stringify(item
), loc
));
726 map
<string
,string
> loc
;
727 loc
["root"] = "default";
729 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
730 "osd." + stringify(item
), loc
));
738 // Trying to insert default under host0 must fail
739 // because it would create a loop.
741 // default --> host0 --> default
744 map
<string
,string
> loc
;
745 loc
["host"] = "host0";
747 EXPECT_EQ(-ELOOP
, c
->insert_item(g_ceph_context
, rootno
, 1.0,
750 // fail when mapping a bucket to the wrong type
752 // create an OSD bucket
754 int r
= c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
755 10, 0, NULL
, NULL
, &osdno
);
757 c
->set_item_name(osdno
, "myosd");
758 map
<string
,string
> loc
;
759 loc
["root"] = "default";
760 // wrongfully pretend the osd is of type host
761 loc
["host"] = "myosd";
764 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
765 "osd." + stringify(item
), loc
));
767 // fail when no location
769 map
<string
,string
> loc
;
771 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
772 "osd." + stringify(item
), loc
));
778 TEST(CrushWrapper
, remove_item
) {
779 auto *c
= new CrushWrapper
;
781 const int ROOT_TYPE
= 2;
782 c
->set_type_name(ROOT_TYPE
, "root");
783 const int HOST_TYPE
= 1;
784 c
->set_type_name(HOST_TYPE
, "host");
785 const int OSD_TYPE
= 0;
786 c
->set_type_name(OSD_TYPE
, "osd");
790 ASSERT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
791 ROOT_TYPE
, 0, NULL
, NULL
, &root
));
792 c
->set_item_name(root
, "root0");
797 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
798 HOST_TYPE
, 0, NULL
, NULL
, &host
);
799 c
->set_item_name(host
, "host0");
802 const int num_osd
= 12;
804 map
<string
, string
> loc
= {{"root", "root0"},
807 for (int item
= 0; item
< num_osd
; item
++) {
808 ASSERT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
809 name
+ to_string(item
), loc
));
812 const int item_to_remove
= num_osd
/ 2;
813 map
<string
, string
> loc
;
814 loc
.insert(c
->get_immediate_parent(item_to_remove
));
815 ASSERT_EQ(0, c
->remove_item(g_ceph_context
, item_to_remove
, true));
817 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item_to_remove
, loc
, &weight
));
822 TEST(CrushWrapper
, item_bucket_names
) {
823 CrushWrapper
*c
= new CrushWrapper
;
825 string name
= "NAME";
826 EXPECT_EQ(-EINVAL
, c
->set_item_name(index
, "\001"));
827 EXPECT_EQ(0, c
->set_item_name(index
, name
));
828 EXPECT_TRUE(c
->name_exists(name
));
829 EXPECT_TRUE(c
->item_exists(index
));
830 EXPECT_EQ(index
, c
->get_item_id(name
));
831 EXPECT_EQ(name
, c
->get_item_name(index
));
835 TEST(CrushWrapper
, bucket_types
) {
836 CrushWrapper
*c
= new CrushWrapper
;
838 string name
= "NAME";
839 c
->set_type_name(index
, name
);
840 EXPECT_EQ(1, c
->get_num_type_names());
841 EXPECT_EQ(index
, c
->get_type_id(name
));
842 EXPECT_EQ(name
, c
->get_type_name(index
));
846 TEST(CrushWrapper
, is_valid_crush_name
) {
847 EXPECT_TRUE(CrushWrapper::is_valid_crush_name("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012456789-_"));
848 EXPECT_FALSE(CrushWrapper::is_valid_crush_name(""));
849 EXPECT_FALSE(CrushWrapper::is_valid_crush_name("\001"));
852 TEST(CrushWrapper
, is_valid_crush_loc
) {
853 map
<string
,string
> loc
;
854 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
855 loc
["good"] = "better";
856 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
858 map
<string
,string
> loc
;
859 loc
["\005"] = "default";
860 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
863 map
<string
,string
> loc
;
864 loc
["host"] = "\003";
865 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
869 TEST(CrushWrapper
, dump_rules
) {
870 CrushWrapper
*c
= new CrushWrapper
;
872 const int ROOT_TYPE
= 1;
873 c
->set_type_name(ROOT_TYPE
, "root");
874 const int OSD_TYPE
= 0;
875 c
->set_type_name(OSD_TYPE
, "osd");
877 string
failure_domain_type("osd");
878 string
root_name("default");
880 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
881 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
882 c
->set_item_name(rootno
, root_name
);
886 pair
<string
,string
> loc
;
888 loc
= c
->get_immediate_parent(item
, &ret
);
889 EXPECT_EQ(-ENOENT
, ret
);
892 map
<string
,string
> loc
;
893 loc
["root"] = root_name
;
895 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
899 // no rule by default
901 Formatter
*f
= Formatter::create("json-pretty");
902 f
->open_array_section("rules");
908 EXPECT_EQ("[]\n", ss
.str());
912 int rule
= c
->add_simple_rule(name
, root_name
, failure_domain_type
, "",
913 "firstn", pg_pool_t::TYPE_ERASURE
);
917 Formatter
*f
= Formatter::create("xml");
922 EXPECT_EQ((unsigned)0, ss
.str().find("<rule><rule_id>0</rule_id><rule_name>NAME</rule_name>"));
926 Formatter
*f
= Formatter::create("xml");
927 c
->dump_rule(rule
, f
);
931 EXPECT_EQ((unsigned)0, ss
.str().find("<rule><rule_id>0</rule_id><rule_name>NAME</rule_name>"));
932 EXPECT_NE(string::npos
,
933 ss
.str().find("<item_name>default</item_name></step>"));
937 c
->get_rule_weight_osd_map(0, &wm
);
938 ASSERT_TRUE(wm
.size() == 1);
939 ASSERT_TRUE(wm
[0] == 1.0);
944 TEST(CrushWrapper
, distance
) {
947 c
.set_type_name(1, "host");
948 c
.set_type_name(2, "rack");
949 c
.set_type_name(3, "root");
951 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW
,
952 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
956 c
.set_item_name(bno
, "default");
958 c
.set_max_devices(10);
960 //JSONFormatter jf(true);
962 map
<string
,string
> loc
;
965 loc
["root"] = "default";
966 c
.insert_item(g_ceph_context
, 0, 1, "osd.0", loc
);
971 loc
["root"] = "default";
972 c
.insert_item(g_ceph_context
, 1, 1, "osd.1", loc
);
977 loc
["root"] = "default";
978 c
.insert_item(g_ceph_context
, 2, 1, "osd.2", loc
);
983 loc
["root"] = "default";
984 c
.insert_item(g_ceph_context
, 3, 1, "osd.3", loc
);
986 vector
<pair
<string
,string
> > ol
;
987 c
.get_full_location_ordered(3, ol
);
988 ASSERT_EQ(3u, ol
.size());
989 ASSERT_EQ(make_pair(string("host"),string("b2")), ol
[0]);
990 ASSERT_EQ(make_pair(string("rack"),string("b")), ol
[1]);
991 ASSERT_EQ(make_pair(string("root"),string("default")), ol
[2]);
996 multimap
<string
,string
> p
;
997 p
.insert(make_pair("host","b2"));
998 p
.insert(make_pair("rack","b"));
999 p
.insert(make_pair("root","default"));
1000 ASSERT_EQ(3, c
.get_common_ancestor_distance(g_ceph_context
, 0, p
));
1001 ASSERT_EQ(3, c
.get_common_ancestor_distance(g_ceph_context
, 1, p
));
1002 ASSERT_EQ(2, c
.get_common_ancestor_distance(g_ceph_context
, 2, p
));
1003 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 3, p
));
1004 ASSERT_EQ(-ENOENT
, c
.get_common_ancestor_distance(g_ceph_context
, 123, p
));
1006 // make sure a "multipath" location will reflect a minimal
1007 // distance for both paths
1008 p
.insert(make_pair("host","b1"));
1009 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 2, p
));
1010 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 3, p
));
1013 TEST(CrushWrapper
, choose_args_compat
) {
1016 c
.set_type_name(1, "host");
1017 c
.set_type_name(2, "rack");
1018 c
.set_type_name(3, "root");
1022 map
<string
,string
> loc
;
1024 loc
["rack"] = "r11";
1025 loc
["root"] = "default";
1027 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1030 loc
["rack"] = "r12";
1031 loc
["root"] = "default";
1033 c
.insert_item(g_ceph_context
, item
, weight
, "osd.2", loc
);
1035 assert(c
.add_simple_rule("rule1", "r11", "host", "",
1036 "firstn", pg_pool_t::TYPE_ERASURE
) >= 0);
1038 int id
= c
.get_item_id("b1");
1040 __u32 weights
= 666 * 0x10000;
1041 crush_weight_set weight_set
;
1042 weight_set
.size
= 1;
1043 weight_set
.weights
= &weights
;
1044 int maxbuckets
= c
.get_max_buckets();
1045 assert(maxbuckets
> 0);
1046 crush_choose_arg choose_args
[maxbuckets
];
1047 memset(choose_args
, '\0', sizeof(crush_choose_arg
) * maxbuckets
);
1048 choose_args
[-1-id
].ids_size
= 0;
1049 choose_args
[-1-id
].weight_set_size
= 1;
1050 choose_args
[-1-id
].weight_set
= &weight_set
;
1051 crush_choose_arg_map arg_map
;
1052 arg_map
.size
= c
.get_max_buckets();
1053 arg_map
.args
= choose_args
;
1055 uint64_t features
= CEPH_FEATURE_CRUSH_TUNABLES5
|CEPH_FEATURE_INCARNATION_2
;
1057 // if the client is capable, encode choose_args
1059 c
.choose_args
[0] = arg_map
;
1061 c
.encode(bl
, features
|CEPH_FEATURE_CRUSH_CHOOSE_ARGS
);
1062 bufferlist::iterator
i(bl
.begin());
1065 ASSERT_EQ(1u, c_new
.choose_args
.size());
1066 ASSERT_EQ(1u, c_new
.choose_args
[0].args
[-1-id
].weight_set_size
);
1067 ASSERT_EQ(weights
, c_new
.choose_args
[0].args
[-1-id
].weight_set
[0].weights
[0]);
1068 ASSERT_EQ(weight
, c_new
.get_bucket_item_weightf(id
, 0));
1071 // if the client is not compatible, copy choose_arg in the weights
1073 c
.choose_args
[0] = arg_map
;
1075 c
.encode(bl
, features
);
1076 c
.choose_args
.clear();
1077 bufferlist::iterator
i(bl
.begin());
1080 ASSERT_EQ(0u, c_new
.choose_args
.size());
1081 ASSERT_EQ((int)weights
, c_new
.get_bucket_item_weight(id
, 0));
1085 TEST(CrushWrapper
, remove_unused_root
) {
1088 c
.set_type_name(1, "host");
1089 c
.set_type_name(2, "rack");
1090 c
.set_type_name(3, "root");
1094 map
<string
,string
> loc
;
1096 loc
["rack"] = "r11";
1097 loc
["root"] = "default";
1099 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1102 loc
["rack"] = "r12";
1103 loc
["root"] = "default";
1104 c
.insert_item(g_ceph_context
, item
, weight
, "osd.2", loc
);
1106 assert(c
.add_simple_rule("rule1", "r11", "host", "",
1107 "firstn", pg_pool_t::TYPE_ERASURE
) >= 0);
1108 ASSERT_TRUE(c
.name_exists("default"));
1109 ASSERT_TRUE(c
.name_exists("r11"));
1110 ASSERT_TRUE(c
.name_exists("r12"));
1111 ASSERT_EQ(c
.remove_root(c
.get_item_id("default"), true), 0);
1112 ASSERT_FALSE(c
.name_exists("default"));
1113 ASSERT_TRUE(c
.name_exists("r11"));
1114 ASSERT_FALSE(c
.name_exists("r12"));
1117 TEST(CrushWrapper
, trim_roots_with_class
) {
1120 c
.set_type_name(1, "root");
1123 map
<string
,string
> loc
;
1124 loc
["root"] = "default";
1127 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1128 int cl
= c
.get_or_create_class_id("ssd");
1129 c
.class_map
[item
] = cl
;
1132 int root_id
= c
.get_item_id("default");
1134 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, &clone_id
), 0);
1136 ASSERT_TRUE(c
.name_exists("default"));
1137 ASSERT_TRUE(c
.name_exists("default~ssd"));
1138 c
.trim_roots_with_class(true); // do nothing because still in use
1139 ASSERT_TRUE(c
.name_exists("default"));
1140 ASSERT_TRUE(c
.name_exists("default~ssd"));
1141 c
.class_bucket
.clear();
1142 c
.trim_roots_with_class(true); // do nothing because still in use
1143 ASSERT_TRUE(c
.name_exists("default"));
1144 ASSERT_FALSE(c
.name_exists("default~ssd"));
1147 TEST(CrushWrapper
, device_class_clone
) {
1150 c
.set_type_name(1, "host");
1151 c
.set_type_name(2, "root");
1153 map
<string
,string
> loc
;
1155 loc
["root"] = "default";
1159 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1160 int cl
= c
.get_or_create_class_id("ssd");
1161 c
.class_map
[item
] = cl
;
1163 int item_no_class
= 2;
1164 c
.insert_item(g_ceph_context
, item_no_class
, weight
, "osd.2", loc
);
1166 c
.reweight(g_ceph_context
);
1168 int root_id
= c
.get_item_id("default");
1170 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, &clone_id
), 0);
1171 ASSERT_TRUE(c
.name_exists("default~ssd"));
1172 ASSERT_EQ(clone_id
, c
.get_item_id("default~ssd"));
1173 ASSERT_TRUE(c
.subtree_contains(clone_id
, item
));
1174 ASSERT_FALSE(c
.subtree_contains(clone_id
, item_no_class
));
1175 ASSERT_TRUE(c
.subtree_contains(root_id
, item_no_class
));
1176 ASSERT_EQ(c
.get_item_weightf(root_id
), 2);
1177 ASSERT_EQ(c
.get_item_weightf(clone_id
), 1);
1178 // cloning again does nothing and returns the existing one
1180 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, &other_clone_id
), 0);
1181 ASSERT_EQ(clone_id
, other_clone_id
);
1182 // invalid arguments
1183 ASSERT_EQ(c
.device_class_clone(12345, cl
, &other_clone_id
), -ECHILD
);
1184 ASSERT_EQ(c
.device_class_clone(root_id
, 12345, &other_clone_id
), -EBADF
);
1187 TEST(CrushWrapper
, split_id_class
) {
1190 c
.set_type_name(1, "root");
1193 map
<string
,string
> loc
;
1194 loc
["root"] = "default";
1197 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1198 int class_id
= c
.get_or_create_class_id("ssd");
1199 c
.class_map
[item
] = class_id
;
1201 int item_id
= c
.get_item_id("default");
1203 ASSERT_EQ(c
.device_class_clone(item_id
, class_id
, &clone_id
), 0);
1204 int retrieved_item_id
;
1205 int retrieved_class_id
;
1206 ASSERT_EQ(c
.split_id_class(clone_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1207 ASSERT_EQ(item_id
, retrieved_item_id
);
1208 ASSERT_EQ(class_id
, retrieved_class_id
);
1210 ASSERT_EQ(c
.split_id_class(item_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1211 ASSERT_EQ(item_id
, retrieved_item_id
);
1212 ASSERT_EQ(-1, retrieved_class_id
);
1215 TEST(CrushWrapper
, populate_and_cleanup_classes
) {
1218 c
.set_type_name(1, "root");
1221 map
<string
,string
> loc
;
1222 loc
["root"] = "default";
1225 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1226 int class_id
= c
.get_or_create_class_id("ssd");
1227 c
.class_map
[item
] = class_id
;
1229 ASSERT_EQ(c
.populate_classes(), 0);
1231 ASSERT_TRUE(c
.name_exists("default~ssd"));
1233 c
.class_bucket
.clear();
1234 ASSERT_EQ(c
.cleanup_classes(), 0);
1235 ASSERT_FALSE(c
.name_exists("default~ssd"));
1238 TEST(CrushWrapper
, class_is_in_use
) {
1241 c
.set_type_name(1, "root");
1244 map
<string
,string
> loc
;
1245 loc
["root"] = "default";
1247 ASSERT_FALSE(c
.class_is_in_use(0));
1250 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1251 int class_id
= c
.get_or_create_class_id("ssd");
1252 c
.class_map
[item
] = class_id
;
1254 ASSERT_TRUE(c
.class_is_in_use(c
.get_class_id("ssd")));
1255 ASSERT_EQ(0, c
.remove_class_name("ssd"));
1256 ASSERT_FALSE(c
.class_is_in_use(c
.get_class_id("ssd")));
1259 TEST(CrushWrapper
, remove_class_name
) {
1263 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1264 ASSERT_GE(0, c
.get_or_create_class_id("ssd"));
1265 ASSERT_EQ(0, c
.remove_class_name("ssd"));
1266 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1269 TEST(CrushWrapper
, try_remap_rule
) {
1270 // build a simple 2 level map
1273 c
.set_type_name(0, "osd");
1274 c
.set_type_name(1, "host");
1275 c
.set_type_name(2, "rack");
1276 c
.set_type_name(3, "root");
1278 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW2
,
1279 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
1283 c
.set_item_name(bno
, "default");
1285 c
.set_max_devices(20);
1287 //JSONFormatter jf(true);
1289 map
<string
,string
> loc
;
1290 loc
["host"] = "foo";
1292 loc
["root"] = "default";
1293 c
.insert_item(g_ceph_context
, 0, 1, "osd.0", loc
);
1294 c
.insert_item(g_ceph_context
, 1, 1, "osd.1", loc
);
1295 c
.insert_item(g_ceph_context
, 2, 1, "osd.2", loc
);
1298 loc
["host"] = "bar";
1300 loc
["root"] = "default";
1301 c
.insert_item(g_ceph_context
, 3, 1, "osd.3", loc
);
1302 c
.insert_item(g_ceph_context
, 4, 1, "osd.4", loc
);
1303 c
.insert_item(g_ceph_context
, 5, 1, "osd.5", loc
);
1306 loc
["host"] = "baz";
1308 loc
["root"] = "default";
1309 c
.insert_item(g_ceph_context
, 6, 1, "osd.6", loc
);
1310 c
.insert_item(g_ceph_context
, 7, 1, "osd.7", loc
);
1311 c
.insert_item(g_ceph_context
, 8, 1, "osd.8", loc
);
1314 loc
["host"] = "qux";
1316 loc
["root"] = "default";
1317 c
.insert_item(g_ceph_context
, 9, 1, "osd.9", loc
);
1318 c
.insert_item(g_ceph_context
, 10, 1, "osd.10", loc
);
1319 c
.insert_item(g_ceph_context
, 11, 1, "osd.11", loc
);
1323 loc
["host"] = "bif";
1325 loc
["root"] = "default";
1326 c
.insert_item(g_ceph_context
, 12, 1, "osd.12", loc
);
1327 c
.insert_item(g_ceph_context
, 13, 1, "osd.13", loc
);
1328 c
.insert_item(g_ceph_context
, 14, 1, "osd.14", loc
);
1332 loc
["host"] = "pop";
1334 loc
["root"] = "default";
1335 c
.insert_item(g_ceph_context
, 15, 1, "osd.15", loc
);
1336 c
.insert_item(g_ceph_context
, 16, 1, "osd.16", loc
);
1337 c
.insert_item(g_ceph_context
, 17, 1, "osd.17", loc
);
1347 // take + choose device + emit
1349 cout
<< "take + choose + emit" << std::endl
;
1351 int rule
= c
.add_simple_rule("one", "default", "osd", "",
1355 vector
<int> orig
= { 0, 3, 9 };
1356 set
<int> overfull
= { 3 };
1357 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1359 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1360 overfull
, underfull
,
1362 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1364 ASSERT_EQ(3u, out
.size());
1365 ASSERT_EQ(0, out
[0]);
1366 ASSERT_EQ(2, out
[1]);
1367 ASSERT_EQ(9, out
[2]);
1369 // make sure we cope with dups between underfull and future values in orig
1370 underfull
= {9, 0, 2, 5};
1373 r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1374 overfull
, underfull
,
1376 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1378 ASSERT_EQ(3u, out
.size());
1379 ASSERT_EQ(1, out
[0]);
1380 ASSERT_EQ(0, out
[1]);
1381 ASSERT_EQ(9, out
[2]);
1386 cout
<< "take + chooseleaf + emit" << std::endl
;
1388 int rule
= c
.add_simple_rule("two", "default", "host", "",
1392 vector
<int> orig
= { 0, 3, 9 };
1393 set
<int> overfull
= { 3 };
1394 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1396 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1397 overfull
, underfull
,
1399 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1401 ASSERT_EQ(3u, out
.size());
1402 ASSERT_EQ(0, out
[0]);
1403 ASSERT_EQ(5, out
[1]);
1404 ASSERT_EQ(9, out
[2]);
1409 cout
<< "take + choose + choose + choose + emit" << std::endl
;
1410 int rule
= c
.add_rule(5, 2, 0, 1, 10, 2);
1412 c
.set_rule_step_take(rule
, 0, bno
);
1413 c
.set_rule_step_choose_indep(rule
, 1, 2, 2);
1414 c
.set_rule_step_choose_indep(rule
, 2, 2, 1);
1415 c
.set_rule_step_choose_indep(rule
, 3, 1, 0);
1416 c
.set_rule_step_emit(rule
, 4);
1418 vector
<int> orig
= { 0, 3, 16, 12 };
1419 set
<int> overfull
= { 3, 12 };
1420 vector
<int> underfull
= { 6, 7, 9, 3, 0, 1, 15, 16, 13, 2, 5, 8, 11 };
1422 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1423 overfull
, underfull
,
1425 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1427 ASSERT_EQ(4u, out
.size());
1428 ASSERT_EQ(0, out
[0]);
1429 ASSERT_EQ(5, out
[1]);
1430 ASSERT_EQ(16, out
[2]);
1431 ASSERT_EQ(13, out
[3]);
1435 r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1436 overfull
, underfull
,
1438 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1440 ASSERT_EQ(3u, out
.size());
1441 ASSERT_EQ(0, out
[0]);
1442 ASSERT_EQ(5, out
[1]);
1443 ASSERT_EQ(16, out
[2]);
1447 int main(int argc
, char **argv
) {
1448 vector
<const char*> args
;
1449 argv_to_vec(argc
, (const char **)argv
, args
);
1452 vector
<const char*> def_args
;
1453 def_args
.push_back("--debug-crush=0");
1454 auto cct
= global_init(&def_args
, args
, CEPH_ENTITY_TYPE_CLIENT
,
1455 CODE_ENVIRONMENT_UTILITY
, 0);
1456 common_init_finish(g_ceph_context
);
1457 ::testing::InitGoogleTest(&argc
, argv
);
1458 return RUN_ALL_TESTS();
1461 // compile-command: "cd ../../../build ; make -j4 unittest_crush_wrapper && valgrind --tool=memcheck bin/unittest_crush_wrapper"