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 "common/ceph_argparse.h"
27 #include "common/common_init.h"
28 #include "include/stringify.h"
29 #include "include/Context.h"
30 #include "osd/osd_types.h"
32 #include "crush/CrushWrapper.h"
36 class CrushWrapperTest
: public ::testing::Test
41 CephInitParameters
params(CEPH_ENTITY_TYPE_CLIENT
);
42 cct
= common_preinit(params
, CODE_ENVIRONMENT_UTILITY
,
43 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
44 cct
->_conf
.set_val("debug_crush", "0");
52 CephContext
*cct
= nullptr;
55 TEST_F(CrushWrapperTest
, get_immediate_parent
) {
56 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
58 const int ROOT_TYPE
= 1;
59 c
->set_type_name(ROOT_TYPE
, "root");
60 const int OSD_TYPE
= 0;
61 c
->set_type_name(OSD_TYPE
, "osd");
64 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
65 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
66 c
->set_item_name(rootno
, "default");
70 pair
<string
,string
> loc
;
72 loc
= c
->get_immediate_parent(item
, &ret
);
73 EXPECT_EQ(-ENOENT
, ret
);
76 map
<string
,string
> loc
;
77 loc
["root"] = "default";
79 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
83 loc
= c
->get_immediate_parent(item
, &ret
);
85 EXPECT_EQ("root", loc
.first
);
86 EXPECT_EQ("default", loc
.second
);
89 TEST_F(CrushWrapperTest
, move_bucket
) {
90 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
92 const int ROOT_TYPE
= 2;
93 c
->set_type_name(ROOT_TYPE
, "root");
94 const int HOST_TYPE
= 1;
95 c
->set_type_name(HOST_TYPE
, "host");
96 const int OSD_TYPE
= 0;
97 c
->set_type_name(OSD_TYPE
, "osd");
100 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
101 ROOT_TYPE
, 0, NULL
, NULL
, &root0
));
102 EXPECT_EQ(0, c
->set_item_name(root0
, "root0"));
105 map
<string
,string
> loc
;
106 loc
["root"] = "root0";
107 loc
["host"] = "host0";
110 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
113 int host0
= c
->get_item_id("host0");
116 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
117 ROOT_TYPE
, 0, NULL
, NULL
, &root1
));
118 EXPECT_EQ(0, c
->set_item_name(root1
, "root1"));
120 map
<string
,string
> loc
;
121 loc
["root"] = "root1";
123 // 0 is not a valid bucket number, must be negative
124 EXPECT_EQ(-EINVAL
, c
->move_bucket(cct
, 0, loc
));
125 // -100 is not an existing bucket
126 EXPECT_EQ(-ENOENT
, c
->move_bucket(cct
, -100, loc
));
127 // move host0 from root0 to root1
129 pair
<string
,string
> loc
;
131 loc
= c
->get_immediate_parent(host0
, &ret
);
133 EXPECT_EQ("root", loc
.first
);
134 EXPECT_EQ("root0", loc
.second
);
136 EXPECT_EQ(0, c
->move_bucket(cct
, host0
, loc
));
138 pair
<string
,string
> loc
;
140 loc
= c
->get_immediate_parent(host0
, &ret
);
142 EXPECT_EQ("root", loc
.first
);
143 EXPECT_EQ("root1", loc
.second
);
147 TEST_F(CrushWrapperTest
, swap_bucket
) {
148 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
150 const int ROOT_TYPE
= 2;
151 c
->set_type_name(ROOT_TYPE
, "root");
152 const int HOST_TYPE
= 1;
153 c
->set_type_name(HOST_TYPE
, "host");
154 const int OSD_TYPE
= 0;
155 c
->set_type_name(OSD_TYPE
, "osd");
158 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
159 ROOT_TYPE
, 0, NULL
, NULL
, &root
));
160 EXPECT_EQ(0, c
->set_item_name(root
, "root"));
163 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
164 HOST_TYPE
, 0, NULL
, NULL
, &a
));
165 EXPECT_EQ(0, c
->set_item_name(a
, "a"));
166 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
167 HOST_TYPE
, 0, NULL
, NULL
, &b
));
168 EXPECT_EQ(0, c
->set_item_name(b
, "b"));
171 map
<string
,string
> loc
;
172 loc
["root"] = "root";
173 EXPECT_EQ(0, c
->move_bucket(cct
, a
, loc
));
176 map
<string
,string
> loc
;
177 loc
["root"] = "root";
179 EXPECT_EQ(0, c
->insert_item(cct
, 0, 1.0, "osd.0", loc
));
180 EXPECT_EQ(0, c
->insert_item(cct
, 1, 1.0, "osd.1", loc
));
181 EXPECT_EQ(0, c
->insert_item(cct
, 2, 1.0, "osd.2", loc
));
184 map
<string
,string
> loc
;
186 EXPECT_EQ(0, c
->insert_item(cct
, 3, 1.0, "osd.3", loc
));
188 ASSERT_EQ(0x30000, c
->get_item_weight(a
));
189 ASSERT_EQ(string("a"), c
->get_item_name(a
));
190 ASSERT_EQ(0x10000, c
->get_item_weight(b
));
191 ASSERT_EQ(string("b"), c
->get_item_name(b
));
192 ASSERT_EQ(a
, c
->get_bucket_item(root
, 0));
193 ASSERT_EQ(0, c
->get_bucket_item(a
, 0));
194 ASSERT_EQ(1, c
->get_bucket_item(a
, 1));
195 ASSERT_EQ(2, c
->get_bucket_item(a
, 2));
196 ASSERT_EQ(3, c
->get_bucket_item(b
, 0));
198 // check if it can swap parent with child
199 ASSERT_EQ(-EINVAL
, c
->swap_bucket(cct
, root
, a
));
201 c
->swap_bucket(cct
, a
, b
);
202 ASSERT_EQ(0x30000, c
->get_item_weight(b
));
203 ASSERT_EQ(string("a"), c
->get_item_name(b
));
204 ASSERT_EQ(0x10000, c
->get_item_weight(a
));
205 ASSERT_EQ(string("b"), c
->get_item_name(a
));
206 ASSERT_EQ(a
, c
->get_bucket_item(root
, 0));
207 ASSERT_EQ(0, c
->get_bucket_item(b
, 0));
208 ASSERT_EQ(1, c
->get_bucket_item(b
, 1));
209 ASSERT_EQ(2, c
->get_bucket_item(b
, 2));
210 ASSERT_EQ(3, c
->get_bucket_item(a
, 0));
213 TEST_F(CrushWrapperTest
, rename_bucket_or_item
) {
214 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
216 const int ROOT_TYPE
= 2;
217 c
->set_type_name(ROOT_TYPE
, "root");
218 const int HOST_TYPE
= 1;
219 c
->set_type_name(HOST_TYPE
, "host");
220 const int OSD_TYPE
= 0;
221 c
->set_type_name(OSD_TYPE
, "osd");
224 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
225 ROOT_TYPE
, 0, NULL
, NULL
, &root0
));
226 EXPECT_EQ(0, c
->set_item_name(root0
, "root0"));
230 map
<string
,string
> loc
;
231 loc
["root"] = "root0";
232 loc
["host"] = "host0";
234 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
239 map
<string
,string
> loc
;
240 loc
["root"] = "root0";
241 loc
["host"] = "host1";
243 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
248 EXPECT_EQ(-EINVAL
, c
->can_rename_item("host0", "????", &ss
));
249 EXPECT_EQ(-EINVAL
, c
->rename_item("host0", "????", &ss
));
250 EXPECT_EQ(-EINVAL
, c
->can_rename_bucket("host0", "????", &ss
));
251 EXPECT_EQ(-EINVAL
, c
->rename_bucket("host0", "????", &ss
));
253 EXPECT_EQ(-EEXIST
, c
->can_rename_item("host0", "host1", &ss
));
254 EXPECT_EQ(-EEXIST
, c
->rename_item("host0", "host1", &ss
));
255 EXPECT_EQ(-EEXIST
, c
->can_rename_bucket("host0", "host1", &ss
));
256 EXPECT_EQ(-EEXIST
, c
->rename_bucket("host0", "host1", &ss
));
258 EXPECT_EQ(-EALREADY
, c
->can_rename_item("gone", "host1", &ss
));
259 EXPECT_EQ(-EALREADY
, c
->rename_item("gone", "host1", &ss
));
260 EXPECT_EQ(-EALREADY
, c
->can_rename_bucket("gone", "host1", &ss
));
261 EXPECT_EQ(-EALREADY
, c
->rename_bucket("gone", "host1", &ss
));
263 EXPECT_EQ(-ENOENT
, c
->can_rename_item("doesnotexist", "somethingelse", &ss
));
264 EXPECT_EQ(-ENOENT
, c
->rename_item("doesnotexist", "somethingelse", &ss
));
265 EXPECT_EQ(-ENOENT
, c
->can_rename_bucket("doesnotexist", "somethingelse", &ss
));
266 EXPECT_EQ(-ENOENT
, c
->rename_bucket("doesnotexist", "somethingelse", &ss
));
268 EXPECT_EQ(-ENOTDIR
, c
->can_rename_bucket("osd.1", "somethingelse", &ss
));
269 EXPECT_EQ(-ENOTDIR
, c
->rename_bucket("osd.1", "somethingelse", &ss
));
271 int host0id
= c
->get_item_id("host0");
272 EXPECT_EQ(0, c
->rename_bucket("host0", "host0renamed", &ss
));
273 EXPECT_EQ(host0id
, c
->get_item_id("host0renamed"));
275 int osd0id
= c
->get_item_id("osd0");
276 EXPECT_EQ(0, c
->rename_item("osd.0", "osd0renamed", &ss
));
277 EXPECT_EQ(osd0id
, c
->get_item_id("osd0renamed"));
280 TEST_F(CrushWrapperTest
, check_item_loc
) {
281 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
283 float expected_weight
= 1.0;
285 // fail if loc is empty
288 map
<string
,string
> loc
;
289 EXPECT_FALSE(c
->check_item_loc(cct
, item
, loc
, &weight
));
292 const int ROOT_TYPE
= 2;
293 c
->set_type_name(ROOT_TYPE
, "root");
294 const int HOST_TYPE
= 1;
295 c
->set_type_name(HOST_TYPE
, "host");
296 const int OSD_TYPE
= 0;
297 c
->set_type_name(OSD_TYPE
, "osd");
300 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
301 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
302 c
->set_item_name(rootno
, "default");
304 // fail because the item is not found at the specified location
307 map
<string
,string
> loc
;
308 loc
["root"] = "default";
309 EXPECT_FALSE(c
->check_item_loc(cct
, item
, loc
, &weight
));
311 // fail because the bucket name does not match an existing bucket
314 map
<string
,string
> loc
;
315 loc
["root"] = "default";
316 const string
HOST("host0");
318 EXPECT_FALSE(c
->check_item_loc(cct
, item
, loc
, &weight
));
320 const string
OSD("osd.0");
322 map
<string
,string
> loc
;
323 loc
["root"] = "default";
324 EXPECT_EQ(0, c
->insert_item(cct
, item
, expected_weight
,
327 // fail because osd.0 is not a bucket and must not be in loc, in
328 // addition to being of the wrong type
331 map
<string
,string
> loc
;
332 loc
["root"] = "osd.0";
333 EXPECT_FALSE(c
->check_item_loc(cct
, item
, loc
, &weight
));
335 // succeed and retrieves the expected weight
338 map
<string
,string
> loc
;
339 loc
["root"] = "default";
340 EXPECT_TRUE(c
->check_item_loc(cct
, item
, loc
, &weight
));
341 EXPECT_EQ(expected_weight
, weight
);
345 TEST_F(CrushWrapperTest
, update_item
) {
346 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
348 const int ROOT_TYPE
= 2;
349 c
->set_type_name(ROOT_TYPE
, "root");
350 const int HOST_TYPE
= 1;
351 c
->set_type_name(HOST_TYPE
, "host");
352 const int OSD_TYPE
= 0;
353 c
->set_type_name(OSD_TYPE
, "osd");
356 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
357 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
358 c
->set_item_name(rootno
, "default");
360 const string
HOST0("host0");
362 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
363 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
364 c
->set_item_name(host0
, HOST0
);
366 const string
HOST1("host1");
368 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
369 HOST_TYPE
, 0, NULL
, NULL
, &host1
);
370 c
->set_item_name(host1
, HOST1
);
374 // fail if invalid names anywhere in loc
376 map
<string
,string
> loc
;
377 loc
["rack"] = "\001";
378 EXPECT_EQ(-EINVAL
, c
->update_item(cct
, item
, 1.0,
379 "osd." + stringify(item
), loc
));
381 // fail if invalid item name
383 map
<string
,string
> loc
;
384 EXPECT_EQ(-EINVAL
, c
->update_item(cct
, item
, 1.0,
387 const string
OSD0("osd.0");
388 const string
OSD1("osd.1");
389 float original_weight
= 1.0;
390 float modified_weight
= 2.0;
393 map
<string
,string
> loc
;
394 loc
["root"] = "default";
396 EXPECT_GE(0.0, c
->get_item_weightf(host0
));
397 EXPECT_EQ(0, c
->insert_item(cct
, item
, original_weight
,
400 // updating nothing changes nothing
401 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
402 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
403 EXPECT_TRUE(c
->check_item_loc(cct
, item
, loc
, &weight
));
404 EXPECT_EQ(0, c
->update_item(cct
, item
, original_weight
,
406 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
407 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
408 EXPECT_TRUE(c
->check_item_loc(cct
, item
, loc
, &weight
));
410 // update the name and weight of the item but not the location
411 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
412 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
413 EXPECT_TRUE(c
->check_item_loc(cct
, item
, loc
, &weight
));
414 EXPECT_EQ(1, c
->update_item(cct
, item
, modified_weight
,
416 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
417 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
418 EXPECT_TRUE(c
->check_item_loc(cct
, item
, loc
, &weight
));
419 c
->set_item_name(item
, OSD0
);
420 c
->adjust_item_weightf(cct
, item
, original_weight
);
422 // update the name and weight of the item and change its location
423 map
<string
,string
> other_loc
;
424 other_loc
["root"] = "default";
425 other_loc
["host"] = HOST1
;
427 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
428 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
429 EXPECT_TRUE(c
->check_item_loc(cct
, item
, loc
, &weight
));
430 EXPECT_FALSE(c
->check_item_loc(cct
, item
, other_loc
, &weight
));
431 EXPECT_EQ(1, c
->update_item(cct
, item
, modified_weight
,
433 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
434 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
435 EXPECT_FALSE(c
->check_item_loc(cct
, item
, loc
, &weight
));
436 EXPECT_TRUE(c
->check_item_loc(cct
, item
, other_loc
, &weight
));
439 TEST_F(CrushWrapperTest
, adjust_item_weight
) {
440 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
442 const int ROOT_TYPE
= 2;
443 c
->set_type_name(ROOT_TYPE
, "root");
444 const int HOST_TYPE
= 1;
445 c
->set_type_name(HOST_TYPE
, "host");
446 const int OSD_TYPE
= 0;
447 c
->set_type_name(OSD_TYPE
, "osd");
450 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
451 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
452 c
->set_item_name(rootno
, "default");
454 const string
HOST0("host0");
456 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
457 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
458 c
->set_item_name(host0
, HOST0
);
460 const string
FAKE("fake");
462 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
463 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
464 c
->set_item_name(hostfake
, FAKE
);
468 // construct crush map
471 map
<string
,string
> loc
;
472 loc
["host"] = "host0";
473 float host_weight
= 2.0;
477 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
478 "osd." + stringify(item
), loc
));
480 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
481 "osd." + stringify(item
), loc
));
483 bucket_id
= c
->get_item_id("host0");
484 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
485 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
487 map
<string
,string
> bloc
;
488 bloc
["root"] = "default";
489 EXPECT_EQ(0, c
->insert_item(cct
, host0
, host_weight
,
494 map
<string
,string
> loc
;
495 loc
["host"] = "fake";
496 float host_weight
= 2.0;
500 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
501 "osd." + stringify(item
), loc
));
503 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
504 "osd." + stringify(item
), loc
));
506 bucket_id
= c
->get_item_id("fake");
507 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
508 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
510 map
<string
,string
> bloc
;
511 bloc
["root"] = "default";
512 EXPECT_EQ(0, c
->insert_item(cct
, hostfake
, host_weight
,
519 // default --> host0 --> osd.0 1.0
523 // +-> fake --> osd.0 1.0
527 // Trying to adjust osd.0 weight to 2.0 in all buckets
528 // Trying to adjust osd.1 weight to 2.0 in host=fake
530 // So the crush map will be:
532 // default --> host0 --> osd.0 2.0
536 // +-> fake --> osd.0 2.0
541 float original_weight
= 1.0;
542 float modified_weight
= 2.0;
543 map
<string
,string
> loc_one
, loc_two
;
544 loc_one
["host"] = "host0";
545 loc_two
["host"] = "fake";
548 EXPECT_EQ(2, c
->adjust_item_weightf(cct
, item
, modified_weight
));
549 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
550 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
553 EXPECT_EQ(1, c
->adjust_item_weightf_in_loc(cct
, item
, modified_weight
, loc_two
));
554 EXPECT_EQ(original_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
555 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
558 TEST_F(CrushWrapperTest
, adjust_subtree_weight
) {
559 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
561 const int ROOT_TYPE
= 2;
562 c
->set_type_name(ROOT_TYPE
, "root");
563 const int HOST_TYPE
= 1;
564 c
->set_type_name(HOST_TYPE
, "host");
565 const int OSD_TYPE
= 0;
566 c
->set_type_name(OSD_TYPE
, "osd");
569 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
570 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
571 c
->set_item_name(rootno
, "default");
573 const string
HOST0("host0");
575 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
576 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
577 c
->set_item_name(host0
, HOST0
);
579 const string
FAKE("fake");
581 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
582 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
583 c
->set_item_name(hostfake
, FAKE
);
587 // construct crush map
590 map
<string
,string
> loc
;
591 loc
["host"] = "host0";
592 float host_weight
= 2.0;
596 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
597 "osd." + stringify(item
), loc
));
599 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
600 "osd." + stringify(item
), loc
));
602 bucket_id
= c
->get_item_id("host0");
603 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
604 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
606 map
<string
,string
> bloc
;
607 bloc
["root"] = "default";
608 EXPECT_EQ(0, c
->insert_item(cct
, host0
, host_weight
,
613 map
<string
,string
> loc
;
614 loc
["host"] = "fake";
615 float host_weight
= 2.0;
619 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
620 "osd." + stringify(item
), loc
));
622 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
623 "osd." + stringify(item
), loc
));
625 bucket_id
= c
->get_item_id("fake");
626 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
627 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
629 map
<string
,string
> bloc
;
630 bloc
["root"] = "default";
631 EXPECT_EQ(0, c
->insert_item(cct
, hostfake
, host_weight
,
635 //cout << "--------before---------" << std::endl;
636 //c->dump_tree(&cout, NULL);
637 ASSERT_EQ(c
->get_bucket_weight(host0
), 131072);
638 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144);
640 int r
= c
->adjust_subtree_weightf(cct
, host0
, 2.0);
641 ASSERT_EQ(r
, 2); // 2 items changed
643 //cout << "--------after---------" << std::endl;
644 //c->dump_tree(&cout, NULL);
646 ASSERT_EQ(c
->get_bucket_weight(host0
), 262144);
647 ASSERT_EQ(c
->get_item_weight(host0
), 262144);
648 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144 + 131072);
651 TEST_F(CrushWrapperTest
, insert_item
) {
652 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
654 const int ROOT_TYPE
= 2;
655 c
->set_type_name(ROOT_TYPE
, "root");
656 const int HOST_TYPE
= 1;
657 c
->set_type_name(HOST_TYPE
, "host");
658 const int OSD_TYPE
= 0;
659 c
->set_type_name(OSD_TYPE
, "osd");
662 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
663 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
664 c
->set_item_name(rootno
, "default");
668 // invalid names anywhere in loc trigger an error
670 map
<string
,string
> loc
;
671 loc
["host"] = "\001";
672 EXPECT_EQ(-EINVAL
, c
->insert_item(cct
, item
, 1.0,
673 "osd." + stringify(item
), loc
));
676 // insert an item in an existing bucket
678 map
<string
,string
> loc
;
679 loc
["root"] = "default";
682 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
683 "osd." + stringify(item
), loc
));
684 int another_item
= item
+ 1;
685 EXPECT_EQ(-EEXIST
, c
->insert_item(cct
, another_item
, 1.0,
686 "osd." + stringify(item
), loc
));
688 // implicit creation of a bucket
690 string name
= "NAME";
691 map
<string
,string
> loc
;
692 loc
["root"] = "default";
696 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
697 "osd." + stringify(item
), loc
));
699 // adding to an existing item name that is not associated with a bucket
701 string name
= "ITEM_WITHOUT_BUCKET";
702 map
<string
,string
> loc
;
703 loc
["root"] = "default";
706 c
->set_item_name(item
, name
);
709 EXPECT_EQ(-EINVAL
, c
->insert_item(cct
, item
, 1.0,
710 "osd." + stringify(item
), loc
));
715 // default --> host0 --> item
717 // Trying to insert the same item higher in the hirarchy will fail
718 // because it would create a loop.
720 // default --> host0 --> item
727 map
<string
,string
> loc
;
728 loc
["root"] = "default";
729 loc
["host"] = "host0";
731 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
732 "osd." + stringify(item
), loc
));
735 map
<string
,string
> loc
;
736 loc
["root"] = "default";
738 EXPECT_EQ(-EINVAL
, c
->insert_item(cct
, item
, 1.0,
739 "osd." + stringify(item
), loc
));
747 // Trying to insert default under host0 must fail
748 // because it would create a loop.
750 // default --> host0 --> default
753 map
<string
,string
> loc
;
754 loc
["host"] = "host0";
756 EXPECT_EQ(-ELOOP
, c
->insert_item(cct
, rootno
, 1.0,
759 // fail when mapping a bucket to the wrong type
761 // create an OSD bucket
763 int r
= c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
764 10, 0, NULL
, NULL
, &osdno
);
766 c
->set_item_name(osdno
, "myosd");
767 map
<string
,string
> loc
;
768 loc
["root"] = "default";
769 // wrongfully pretend the osd is of type host
770 loc
["host"] = "myosd";
773 EXPECT_EQ(-EINVAL
, c
->insert_item(cct
, item
, 1.0,
774 "osd." + stringify(item
), loc
));
776 // fail when no location
778 map
<string
,string
> loc
;
780 EXPECT_EQ(-EINVAL
, c
->insert_item(cct
, item
, 1.0,
781 "osd." + stringify(item
), loc
));
785 TEST_F(CrushWrapperTest
, remove_item
) {
786 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
788 const int ROOT_TYPE
= 2;
789 c
->set_type_name(ROOT_TYPE
, "root");
790 const int HOST_TYPE
= 1;
791 c
->set_type_name(HOST_TYPE
, "host");
792 const int OSD_TYPE
= 0;
793 c
->set_type_name(OSD_TYPE
, "osd");
797 ASSERT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
798 ROOT_TYPE
, 0, NULL
, NULL
, &root
));
799 c
->set_item_name(root
, "root0");
804 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
805 HOST_TYPE
, 0, NULL
, NULL
, &host
);
806 c
->set_item_name(host
, "host0");
809 const int num_osd
= 12;
811 map
<string
, string
> loc
= {{"root", "root0"},
814 for (int item
= 0; item
< num_osd
; item
++) {
815 ASSERT_EQ(0, c
->insert_item(cct
, item
, 1.0,
816 name
+ to_string(item
), loc
));
819 const int item_to_remove
= num_osd
/ 2;
820 map
<string
, string
> loc
;
821 loc
.insert(c
->get_immediate_parent(item_to_remove
));
822 ASSERT_EQ(0, c
->remove_item(cct
, item_to_remove
, true));
824 EXPECT_FALSE(c
->check_item_loc(cct
, item_to_remove
, loc
, &weight
));
827 TEST_F(CrushWrapperTest
, item_bucket_names
) {
828 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
830 string name
= "NAME";
831 EXPECT_EQ(-EINVAL
, c
->set_item_name(index
, "\001"));
832 EXPECT_EQ(0, c
->set_item_name(index
, name
));
833 EXPECT_TRUE(c
->name_exists(name
));
834 EXPECT_TRUE(c
->item_exists(index
));
835 EXPECT_EQ(index
, c
->get_item_id(name
));
836 EXPECT_EQ(name
, c
->get_item_name(index
));
839 TEST_F(CrushWrapperTest
, bucket_types
) {
840 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
842 string name
= "NAME";
843 c
->set_type_name(index
, name
);
844 EXPECT_EQ(1, c
->get_num_type_names());
845 EXPECT_EQ(index
, c
->get_type_id(name
));
846 EXPECT_EQ(name
, c
->get_type_name(index
));
849 TEST_F(CrushWrapperTest
, is_valid_crush_name
) {
850 EXPECT_TRUE(CrushWrapper::is_valid_crush_name("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012456789-_"));
851 EXPECT_FALSE(CrushWrapper::is_valid_crush_name(""));
852 EXPECT_FALSE(CrushWrapper::is_valid_crush_name("\001"));
855 TEST_F(CrushWrapperTest
, is_valid_crush_loc
) {
856 map
<string
,string
> loc
;
857 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(cct
, loc
));
858 loc
["good"] = "better";
859 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(cct
, loc
));
861 map
<string
,string
> loc
;
862 loc
["\005"] = "default";
863 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(cct
, loc
));
866 map
<string
,string
> loc
;
867 loc
["host"] = "\003";
868 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(cct
, loc
));
872 TEST_F(CrushWrapperTest
, dump_rules
) {
873 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
875 const int ROOT_TYPE
= 1;
876 c
->set_type_name(ROOT_TYPE
, "root");
877 const int OSD_TYPE
= 0;
878 c
->set_type_name(OSD_TYPE
, "osd");
880 string
failure_domain_type("osd");
881 string
root_name("default");
883 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
884 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
885 c
->set_item_name(rootno
, root_name
);
889 pair
<string
,string
> loc
;
891 loc
= c
->get_immediate_parent(item
, &ret
);
892 EXPECT_EQ(-ENOENT
, ret
);
895 map
<string
,string
> loc
;
896 loc
["root"] = root_name
;
898 EXPECT_EQ(0, c
->insert_item(cct
, item
, 1.0,
902 // no rule by default
904 auto f
= Formatter::create_unique("json-pretty");
905 f
->open_array_section("rules");
906 c
->dump_rules(f
.get());
910 EXPECT_EQ("[]\n", ss
.str());
914 int rule
= c
->add_simple_rule(name
, root_name
, failure_domain_type
, "",
915 "firstn", pg_pool_t::TYPE_ERASURE
);
919 auto f
= Formatter::create_unique("xml");
920 c
->dump_rules(f
.get());
923 EXPECT_EQ((unsigned)0, ss
.str().find("<rule><rule_id>0</rule_id><rule_name>NAME</rule_name>"));
927 auto f
= Formatter::create_unique("xml");
928 c
->dump_rule(rule
, f
.get());
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);
942 TEST_F(CrushWrapperTest
, distance
) {
945 c
.set_type_name(1, "host");
946 c
.set_type_name(2, "rack");
947 c
.set_type_name(3, "root");
949 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW
,
950 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
954 c
.set_item_name(bno
, "default");
956 c
.set_max_devices(10);
958 //JSONFormatter jf(true);
960 map
<string
,string
> loc
;
963 loc
["root"] = "default";
964 c
.insert_item(cct
, 0, 1, "osd.0", loc
);
969 loc
["root"] = "default";
970 c
.insert_item(cct
, 1, 1, "osd.1", loc
);
975 loc
["root"] = "default";
976 c
.insert_item(cct
, 2, 1, "osd.2", loc
);
981 loc
["root"] = "default";
982 c
.insert_item(cct
, 3, 1, "osd.3", loc
);
984 vector
<pair
<string
,string
> > ol
;
985 c
.get_full_location_ordered(3, ol
);
986 ASSERT_EQ(3u, ol
.size());
987 ASSERT_EQ(make_pair(string("host"),string("b2")), ol
[0]);
988 ASSERT_EQ(make_pair(string("rack"),string("b")), ol
[1]);
989 ASSERT_EQ(make_pair(string("root"),string("default")), ol
[2]);
994 multimap
<string
,string
> p
;
995 p
.insert(make_pair("host","b2"));
996 p
.insert(make_pair("rack","b"));
997 p
.insert(make_pair("root","default"));
998 ASSERT_EQ(3, c
.get_common_ancestor_distance(cct
, 0, p
));
999 ASSERT_EQ(3, c
.get_common_ancestor_distance(cct
, 1, p
));
1000 ASSERT_EQ(2, c
.get_common_ancestor_distance(cct
, 2, p
));
1001 ASSERT_EQ(1, c
.get_common_ancestor_distance(cct
, 3, p
));
1002 ASSERT_EQ(-ENOENT
, c
.get_common_ancestor_distance(cct
, 123, p
));
1004 // make sure a "multipath" location will reflect a minimal
1005 // distance for both paths
1006 p
.insert(make_pair("host","b1"));
1007 ASSERT_EQ(1, c
.get_common_ancestor_distance(cct
, 2, p
));
1008 ASSERT_EQ(1, c
.get_common_ancestor_distance(cct
, 3, p
));
1011 TEST_F(CrushWrapperTest
, choose_args_compat
) {
1014 c
.set_type_name(1, "host");
1015 c
.set_type_name(2, "rack");
1016 c
.set_type_name(3, "root");
1020 map
<string
,string
> loc
;
1022 loc
["rack"] = "r11";
1023 loc
["root"] = "default";
1025 c
.insert_item(cct
, item
, weight
, "osd.1", loc
);
1028 loc
["rack"] = "r12";
1029 loc
["root"] = "default";
1031 c
.insert_item(cct
, item
, weight
, "osd.2", loc
);
1033 ceph_assert(c
.add_simple_rule("rule1", "r11", "host", "",
1034 "firstn", pg_pool_t::TYPE_ERASURE
) >= 0);
1036 int id
= c
.get_item_id("b1");
1038 __u32 weights
= 666 * 0x10000;
1039 crush_weight_set weight_set
;
1040 weight_set
.size
= 1;
1041 weight_set
.weights
= &weights
;
1042 int maxbuckets
= c
.get_max_buckets();
1043 ceph_assert(maxbuckets
> 0);
1044 crush_choose_arg choose_args
[maxbuckets
];
1045 memset(choose_args
, '\0', sizeof(crush_choose_arg
) * maxbuckets
);
1046 choose_args
[-1-id
].ids_size
= 0;
1047 choose_args
[-1-id
].weight_set_positions
= 1;
1048 choose_args
[-1-id
].weight_set
= &weight_set
;
1049 crush_choose_arg_map arg_map
;
1050 arg_map
.size
= c
.get_max_buckets();
1051 arg_map
.args
= choose_args
;
1053 uint64_t features
= CEPH_FEATURE_CRUSH_TUNABLES5
|CEPH_FEATURE_INCARNATION_2
;
1054 int64_t caid
= CrushWrapper::DEFAULT_CHOOSE_ARGS
;
1056 // if the client is capable, encode choose_args
1058 c
.choose_args
[caid
] = arg_map
;
1060 c
.encode(bl
, features
|CEPH_FEATURE_CRUSH_CHOOSE_ARGS
);
1061 auto i
= bl
.cbegin();
1064 ASSERT_EQ(1u, c_new
.choose_args
.size());
1065 ASSERT_EQ(1u, c_new
.choose_args
[caid
].args
[-1-id
].weight_set_positions
);
1066 ASSERT_EQ(weights
, c_new
.choose_args
[caid
].args
[-1-id
].weight_set
[0].weights
[0]);
1067 ASSERT_EQ(weight
, c_new
.get_bucket_item_weightf(id
, 0));
1070 // if the client is not compatible, copy choose_arg in the weights
1072 c
.choose_args
[caid
] = arg_map
;
1074 c
.encode(bl
, features
);
1075 c
.choose_args
.clear();
1076 auto i
= bl
.cbegin();
1079 ASSERT_EQ(0u, c_new
.choose_args
.size());
1080 ASSERT_EQ((int)weights
, c_new
.get_bucket_item_weight(id
, 0));
1084 TEST_F(CrushWrapperTest
, remove_root
) {
1087 c
.set_type_name(1, "host");
1088 c
.set_type_name(2, "rack");
1089 c
.set_type_name(3, "root");
1093 map
<string
,string
> loc
;
1095 loc
["rack"] = "r11";
1096 loc
["root"] = "default";
1098 c
.insert_item(cct
, item
, weight
, "osd.1", loc
);
1101 loc
["rack"] = "r12";
1102 loc
["root"] = "default";
1103 c
.insert_item(cct
, item
, weight
, "osd.2", loc
);
1105 ceph_assert(c
.add_simple_rule("rule1", "r11", "host", "",
1106 "firstn", pg_pool_t::TYPE_ERASURE
) >= 0);
1107 ASSERT_TRUE(c
.name_exists("default"));
1108 ASSERT_TRUE(c
.name_exists("r11"));
1109 ASSERT_TRUE(c
.name_exists("r12"));
1110 ASSERT_EQ(c
.remove_root(cct
, c
.get_item_id("default")), 0);
1111 ASSERT_FALSE(c
.name_exists("default"));
1112 ASSERT_FALSE(c
.name_exists("r11"));
1113 ASSERT_FALSE(c
.name_exists("r12"));
1116 TEST_F(CrushWrapperTest
, trim_roots_with_class
) {
1119 c
.set_type_name(1, "root");
1122 map
<string
,string
> loc
;
1123 loc
["root"] = "default";
1126 c
.insert_item(cct
, item
, weight
, "osd.1", loc
);
1127 int cl
= c
.get_or_create_class_id("ssd");
1128 c
.class_map
[item
] = cl
;
1131 int root_id
= c
.get_item_id("default");
1133 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1134 map
<int,map
<int,vector
<int>>> cmap_item_weight
; // cargs -> bno -> weights
1135 set
<int32_t> used_ids
;
1137 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, old_class_bucket
, used_ids
,
1138 &clone_id
, &cmap_item_weight
), 0);
1140 ASSERT_TRUE(c
.name_exists("default"));
1141 ASSERT_TRUE(c
.name_exists("default~ssd"));
1142 c
.trim_roots_with_class(cct
);
1143 ASSERT_TRUE(c
.name_exists("default"));
1144 ASSERT_FALSE(c
.name_exists("default~ssd"));
1147 TEST_F(CrushWrapperTest
, 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(cct
, 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(cct
, item_no_class
, weight
, "osd.2", loc
);
1168 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1169 map
<int,map
<int,vector
<int>>> cmap_item_weight
; // cargs -> bno -> weights
1170 set
<int32_t> used_ids
;
1171 int root_id
= c
.get_item_id("default");
1173 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, old_class_bucket
, used_ids
,
1174 &clone_id
, &cmap_item_weight
), 0);
1175 ASSERT_TRUE(c
.name_exists("default~ssd"));
1176 ASSERT_EQ(clone_id
, c
.get_item_id("default~ssd"));
1177 ASSERT_TRUE(c
.subtree_contains(clone_id
, item
));
1178 ASSERT_FALSE(c
.subtree_contains(clone_id
, item_no_class
));
1179 ASSERT_TRUE(c
.subtree_contains(root_id
, item_no_class
));
1180 ASSERT_EQ(c
.get_item_weightf(root_id
), 2);
1181 ASSERT_EQ(c
.get_item_weightf(clone_id
), 1);
1182 // cloning again does nothing and returns the existing one
1184 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, old_class_bucket
, used_ids
,
1185 &other_clone_id
, &cmap_item_weight
), 0);
1186 ASSERT_EQ(clone_id
, other_clone_id
);
1187 // invalid arguments
1188 ASSERT_EQ(c
.device_class_clone(12345, cl
, old_class_bucket
, used_ids
,
1189 &other_clone_id
, &cmap_item_weight
), -ECHILD
);
1190 ASSERT_EQ(c
.device_class_clone(root_id
, 12345, old_class_bucket
, used_ids
,
1191 &other_clone_id
, &cmap_item_weight
), -EBADF
);
1194 TEST_F(CrushWrapperTest
, split_id_class
) {
1197 c
.set_type_name(1, "root");
1200 map
<string
,string
> loc
;
1201 loc
["root"] = "default";
1204 c
.insert_item(cct
, item
, weight
, "osd.1", loc
);
1205 int class_id
= c
.get_or_create_class_id("ssd");
1206 c
.class_map
[item
] = class_id
;
1208 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1209 map
<int,map
<int,vector
<int>>> cmap_item_weight
; // cargs -> bno -> weights
1210 set
<int32_t> used_ids
;
1211 int item_id
= c
.get_item_id("default");
1213 ASSERT_EQ(c
.device_class_clone(item_id
, class_id
, old_class_bucket
, used_ids
,
1214 &clone_id
, &cmap_item_weight
), 0);
1215 int retrieved_item_id
;
1216 int retrieved_class_id
;
1217 ASSERT_EQ(c
.split_id_class(clone_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1218 ASSERT_EQ(item_id
, retrieved_item_id
);
1219 ASSERT_EQ(class_id
, retrieved_class_id
);
1221 ASSERT_EQ(c
.split_id_class(item_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1222 ASSERT_EQ(item_id
, retrieved_item_id
);
1223 ASSERT_EQ(-1, retrieved_class_id
);
1226 TEST_F(CrushWrapperTest
, populate_classes
) {
1229 c
.set_type_name(1, "root");
1232 map
<string
,string
> loc
;
1233 loc
["root"] = "default";
1236 c
.insert_item(cct
, item
, weight
, "osd.1", loc
);
1237 int class_id
= c
.get_or_create_class_id("ssd");
1238 c
.class_map
[item
] = class_id
;
1240 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1241 ASSERT_EQ(c
.populate_classes(old_class_bucket
), 0);
1243 ASSERT_TRUE(c
.name_exists("default~ssd"));
1245 old_class_bucket
= c
.class_bucket
;
1246 ASSERT_EQ(c
.populate_classes(old_class_bucket
), 0);
1247 ASSERT_EQ(old_class_bucket
, c
.class_bucket
);
1250 TEST_F(CrushWrapperTest
, remove_class_name
) {
1254 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1255 ASSERT_GE(0, c
.get_or_create_class_id("ssd"));
1256 ASSERT_EQ(0, c
.remove_class_name("ssd"));
1257 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1260 TEST_F(CrushWrapperTest
, try_remap_rule
) {
1261 // build a simple 2 level map
1264 c
.set_type_name(0, "osd");
1265 c
.set_type_name(1, "host");
1266 c
.set_type_name(2, "rack");
1267 c
.set_type_name(3, "root");
1269 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW2
,
1270 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
1274 c
.set_item_name(bno
, "default");
1276 c
.set_max_devices(20);
1278 //JSONFormatter jf(true);
1280 map
<string
,string
> loc
;
1281 loc
["host"] = "foo";
1283 loc
["root"] = "default";
1284 c
.insert_item(cct
, 0, 1, "osd.0", loc
);
1285 c
.insert_item(cct
, 1, 1, "osd.1", loc
);
1286 c
.insert_item(cct
, 2, 1, "osd.2", loc
);
1289 loc
["host"] = "bar";
1291 loc
["root"] = "default";
1292 c
.insert_item(cct
, 3, 1, "osd.3", loc
);
1293 c
.insert_item(cct
, 4, 1, "osd.4", loc
);
1294 c
.insert_item(cct
, 5, 1, "osd.5", loc
);
1297 loc
["host"] = "baz";
1299 loc
["root"] = "default";
1300 c
.insert_item(cct
, 6, 1, "osd.6", loc
);
1301 c
.insert_item(cct
, 7, 1, "osd.7", loc
);
1302 c
.insert_item(cct
, 8, 1, "osd.8", loc
);
1305 loc
["host"] = "qux";
1307 loc
["root"] = "default";
1308 c
.insert_item(cct
, 9, 1, "osd.9", loc
);
1309 c
.insert_item(cct
, 10, 1, "osd.10", loc
);
1310 c
.insert_item(cct
, 11, 1, "osd.11", loc
);
1314 loc
["host"] = "bif";
1316 loc
["root"] = "default";
1317 c
.insert_item(cct
, 12, 1, "osd.12", loc
);
1318 c
.insert_item(cct
, 13, 1, "osd.13", loc
);
1319 c
.insert_item(cct
, 14, 1, "osd.14", loc
);
1323 loc
["host"] = "pop";
1325 loc
["root"] = "default";
1326 c
.insert_item(cct
, 15, 1, "osd.15", loc
);
1327 c
.insert_item(cct
, 16, 1, "osd.16", loc
);
1328 c
.insert_item(cct
, 17, 1, "osd.17", loc
);
1338 // take + choose device + emit
1340 cout
<< "take + choose + emit" << std::endl
;
1342 int rule
= c
.add_simple_rule("one", "default", "osd", "",
1346 vector
<int> orig
= { 0, 3, 9 };
1347 set
<int> overfull
= { 3 };
1348 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1349 vector
<int> more_underfull
= {};
1351 int r
= c
.try_remap_rule(cct
, rule
, 3,
1352 overfull
, underfull
, more_underfull
,
1354 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1356 ASSERT_EQ(3u, out
.size());
1357 ASSERT_EQ(0, out
[0]);
1358 ASSERT_EQ(2, out
[1]);
1359 ASSERT_EQ(9, out
[2]);
1361 // make sure we cope with dups between underfull and future values in orig
1362 underfull
= {9, 0, 2, 5};
1365 r
= c
.try_remap_rule(cct
, rule
, 3,
1366 overfull
, underfull
, more_underfull
,
1368 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1370 ASSERT_EQ(3u, out
.size());
1371 ASSERT_EQ(1, out
[0]);
1372 ASSERT_EQ(0, out
[1]);
1373 ASSERT_EQ(9, out
[2]);
1375 // Check that more_underfull is used when underfull runs out
1377 overfull
= { 3, 9 };
1379 more_underfull
= { 5, 8, 11 };
1380 r
= c
.try_remap_rule(cct
, rule
, 3,
1381 overfull
, underfull
, more_underfull
,
1383 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1385 ASSERT_EQ(3u, out
.size());
1386 ASSERT_EQ(0, out
[0]);
1387 ASSERT_EQ(2, out
[1]);
1388 ASSERT_EQ(5, out
[2]);
1393 cout
<< "take + chooseleaf + emit" << std::endl
;
1395 int rule
= c
.add_simple_rule("two", "default", "host", "",
1399 vector
<int> orig
= { 0, 3, 9 };
1400 set
<int> overfull
= { 3 };
1401 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1402 vector
<int> more_underfull
= { };
1404 int r
= c
.try_remap_rule(cct
, rule
, 3,
1405 overfull
, underfull
, more_underfull
,
1407 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1409 ASSERT_EQ(3u, out
.size());
1410 ASSERT_EQ(0, out
[0]);
1411 ASSERT_EQ(5, out
[1]);
1412 ASSERT_EQ(9, out
[2]);
1417 cout
<< "take + choose + choose + choose + emit" << std::endl
;
1418 int rule
= c
.add_rule(2, 5, 0);
1420 c
.set_rule_step_take(rule
, 0, bno
);
1421 c
.set_rule_step_choose_indep(rule
, 1, 2, 2);
1422 c
.set_rule_step_choose_indep(rule
, 2, 2, 1);
1423 c
.set_rule_step_choose_indep(rule
, 3, 1, 0);
1424 c
.set_rule_step_emit(rule
, 4);
1426 vector
<int> orig
= { 0, 3, 16, 12 };
1427 set
<int> overfull
= { 3, 12 };
1428 vector
<int> underfull
= { 6, 7, 9, 3, 0, 1, 15, 16, 13, 2, 5, 8, 11 };
1429 vector
<int> more_underfull
= { };
1431 int r
= c
.try_remap_rule(cct
, rule
, 3,
1432 overfull
, underfull
, more_underfull
,
1434 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1436 ASSERT_EQ(4u, out
.size());
1437 ASSERT_EQ(0, out
[0]);
1438 ASSERT_EQ(5, out
[1]);
1439 ASSERT_EQ(16, out
[2]);
1440 ASSERT_EQ(13, out
[3]);
1444 r
= c
.try_remap_rule(cct
, rule
, 3,
1445 overfull
, underfull
, more_underfull
,
1447 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1449 ASSERT_EQ(3u, out
.size());
1450 ASSERT_EQ(0, out
[0]);
1451 ASSERT_EQ(5, out
[1]);
1452 ASSERT_EQ(16, out
[2]);
1457 // compile-command: "cd ../../../build ; make -j4 unittest_crush_wrapper && valgrind --tool=memcheck bin/unittest_crush_wrapper"