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 std::unique_ptr
<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
);
69 TEST(CrushWrapper
, move_bucket
) {
70 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
72 const int ROOT_TYPE
= 2;
73 c
->set_type_name(ROOT_TYPE
, "root");
74 const int HOST_TYPE
= 1;
75 c
->set_type_name(HOST_TYPE
, "host");
76 const int OSD_TYPE
= 0;
77 c
->set_type_name(OSD_TYPE
, "osd");
80 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
81 ROOT_TYPE
, 0, NULL
, NULL
, &root0
));
82 EXPECT_EQ(0, c
->set_item_name(root0
, "root0"));
85 map
<string
,string
> loc
;
86 loc
["root"] = "root0";
87 loc
["host"] = "host0";
90 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
93 int host0
= c
->get_item_id("host0");
96 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
97 ROOT_TYPE
, 0, NULL
, NULL
, &root1
));
98 EXPECT_EQ(0, c
->set_item_name(root1
, "root1"));
100 map
<string
,string
> loc
;
101 loc
["root"] = "root1";
103 // 0 is not a valid bucket number, must be negative
104 EXPECT_EQ(-EINVAL
, c
->move_bucket(g_ceph_context
, 0, loc
));
105 // -100 is not an existing bucket
106 EXPECT_EQ(-ENOENT
, c
->move_bucket(g_ceph_context
, -100, loc
));
107 // move host0 from root0 to root1
109 pair
<string
,string
> loc
;
111 loc
= c
->get_immediate_parent(host0
, &ret
);
113 EXPECT_EQ("root", loc
.first
);
114 EXPECT_EQ("root0", loc
.second
);
116 EXPECT_EQ(0, c
->move_bucket(g_ceph_context
, host0
, loc
));
118 pair
<string
,string
> loc
;
120 loc
= c
->get_immediate_parent(host0
, &ret
);
122 EXPECT_EQ("root", loc
.first
);
123 EXPECT_EQ("root1", loc
.second
);
127 TEST(CrushWrapper
, swap_bucket
) {
128 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
130 const int ROOT_TYPE
= 2;
131 c
->set_type_name(ROOT_TYPE
, "root");
132 const int HOST_TYPE
= 1;
133 c
->set_type_name(HOST_TYPE
, "host");
134 const int OSD_TYPE
= 0;
135 c
->set_type_name(OSD_TYPE
, "osd");
138 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
139 ROOT_TYPE
, 0, NULL
, NULL
, &root
));
140 EXPECT_EQ(0, c
->set_item_name(root
, "root"));
143 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
144 HOST_TYPE
, 0, NULL
, NULL
, &a
));
145 EXPECT_EQ(0, c
->set_item_name(a
, "a"));
146 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW2
, CRUSH_HASH_RJENKINS1
,
147 HOST_TYPE
, 0, NULL
, NULL
, &b
));
148 EXPECT_EQ(0, c
->set_item_name(b
, "b"));
151 map
<string
,string
> loc
;
152 loc
["root"] = "root";
153 EXPECT_EQ(0, c
->move_bucket(g_ceph_context
, a
, loc
));
156 map
<string
,string
> loc
;
157 loc
["root"] = "root";
159 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 0, 1.0, "osd.0", loc
));
160 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 1, 1.0, "osd.1", loc
));
161 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 2, 1.0, "osd.2", loc
));
164 map
<string
,string
> loc
;
166 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, 3, 1.0, "osd.3", loc
));
168 ASSERT_EQ(0x30000, c
->get_item_weight(a
));
169 ASSERT_EQ(string("a"), c
->get_item_name(a
));
170 ASSERT_EQ(0x10000, c
->get_item_weight(b
));
171 ASSERT_EQ(string("b"), c
->get_item_name(b
));
172 ASSERT_EQ(a
, c
->get_bucket_item(root
, 0));
173 ASSERT_EQ(0, c
->get_bucket_item(a
, 0));
174 ASSERT_EQ(1, c
->get_bucket_item(a
, 1));
175 ASSERT_EQ(2, c
->get_bucket_item(a
, 2));
176 ASSERT_EQ(3, c
->get_bucket_item(b
, 0));
178 c
->swap_bucket(g_ceph_context
, a
, b
);
179 ASSERT_EQ(0x30000, c
->get_item_weight(b
));
180 ASSERT_EQ(string("a"), c
->get_item_name(b
));
181 ASSERT_EQ(0x10000, c
->get_item_weight(a
));
182 ASSERT_EQ(string("b"), c
->get_item_name(a
));
183 ASSERT_EQ(a
, c
->get_bucket_item(root
, 0));
184 ASSERT_EQ(0, c
->get_bucket_item(b
, 0));
185 ASSERT_EQ(1, c
->get_bucket_item(b
, 1));
186 ASSERT_EQ(2, c
->get_bucket_item(b
, 2));
187 ASSERT_EQ(3, c
->get_bucket_item(a
, 0));
190 TEST(CrushWrapper
, rename_bucket_or_item
) {
191 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
193 const int ROOT_TYPE
= 2;
194 c
->set_type_name(ROOT_TYPE
, "root");
195 const int HOST_TYPE
= 1;
196 c
->set_type_name(HOST_TYPE
, "host");
197 const int OSD_TYPE
= 0;
198 c
->set_type_name(OSD_TYPE
, "osd");
201 EXPECT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
202 ROOT_TYPE
, 0, NULL
, NULL
, &root0
));
203 EXPECT_EQ(0, c
->set_item_name(root0
, "root0"));
207 map
<string
,string
> loc
;
208 loc
["root"] = "root0";
209 loc
["host"] = "host0";
211 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
216 map
<string
,string
> loc
;
217 loc
["root"] = "root0";
218 loc
["host"] = "host1";
220 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
225 EXPECT_EQ(-EINVAL
, c
->can_rename_item("host0", "????", &ss
));
226 EXPECT_EQ(-EINVAL
, c
->rename_item("host0", "????", &ss
));
227 EXPECT_EQ(-EINVAL
, c
->can_rename_bucket("host0", "????", &ss
));
228 EXPECT_EQ(-EINVAL
, c
->rename_bucket("host0", "????", &ss
));
230 EXPECT_EQ(-EEXIST
, c
->can_rename_item("host0", "host1", &ss
));
231 EXPECT_EQ(-EEXIST
, c
->rename_item("host0", "host1", &ss
));
232 EXPECT_EQ(-EEXIST
, c
->can_rename_bucket("host0", "host1", &ss
));
233 EXPECT_EQ(-EEXIST
, c
->rename_bucket("host0", "host1", &ss
));
235 EXPECT_EQ(-EALREADY
, c
->can_rename_item("gone", "host1", &ss
));
236 EXPECT_EQ(-EALREADY
, c
->rename_item("gone", "host1", &ss
));
237 EXPECT_EQ(-EALREADY
, c
->can_rename_bucket("gone", "host1", &ss
));
238 EXPECT_EQ(-EALREADY
, c
->rename_bucket("gone", "host1", &ss
));
240 EXPECT_EQ(-ENOENT
, c
->can_rename_item("doesnotexist", "somethingelse", &ss
));
241 EXPECT_EQ(-ENOENT
, c
->rename_item("doesnotexist", "somethingelse", &ss
));
242 EXPECT_EQ(-ENOENT
, c
->can_rename_bucket("doesnotexist", "somethingelse", &ss
));
243 EXPECT_EQ(-ENOENT
, c
->rename_bucket("doesnotexist", "somethingelse", &ss
));
245 EXPECT_EQ(-ENOTDIR
, c
->can_rename_bucket("osd.1", "somethingelse", &ss
));
246 EXPECT_EQ(-ENOTDIR
, c
->rename_bucket("osd.1", "somethingelse", &ss
));
248 int host0id
= c
->get_item_id("host0");
249 EXPECT_EQ(0, c
->rename_bucket("host0", "host0renamed", &ss
));
250 EXPECT_EQ(host0id
, c
->get_item_id("host0renamed"));
252 int osd0id
= c
->get_item_id("osd0");
253 EXPECT_EQ(0, c
->rename_item("osd.0", "osd0renamed", &ss
));
254 EXPECT_EQ(osd0id
, c
->get_item_id("osd0renamed"));
257 TEST(CrushWrapper
, check_item_loc
) {
258 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
260 float expected_weight
= 1.0;
262 // fail if loc is empty
265 map
<string
,string
> loc
;
266 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
269 const int ROOT_TYPE
= 2;
270 c
->set_type_name(ROOT_TYPE
, "root");
271 const int HOST_TYPE
= 1;
272 c
->set_type_name(HOST_TYPE
, "host");
273 const int OSD_TYPE
= 0;
274 c
->set_type_name(OSD_TYPE
, "osd");
277 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
278 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
279 c
->set_item_name(rootno
, "default");
281 // fail because the item is not found at the specified location
284 map
<string
,string
> loc
;
285 loc
["root"] = "default";
286 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
288 // fail because the bucket name does not match an existing bucket
291 map
<string
,string
> loc
;
292 loc
["root"] = "default";
293 const string
HOST("host0");
295 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
297 const string
OSD("osd.0");
299 map
<string
,string
> loc
;
300 loc
["root"] = "default";
301 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, expected_weight
,
304 // fail because osd.0 is not a bucket and must not be in loc, in
305 // addition to being of the wrong type
308 map
<string
,string
> loc
;
309 loc
["root"] = "osd.0";
310 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
312 // succeed and retrieves the expected weight
315 map
<string
,string
> loc
;
316 loc
["root"] = "default";
317 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
318 EXPECT_EQ(expected_weight
, weight
);
322 TEST(CrushWrapper
, update_item
) {
323 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
325 const int ROOT_TYPE
= 2;
326 c
->set_type_name(ROOT_TYPE
, "root");
327 const int HOST_TYPE
= 1;
328 c
->set_type_name(HOST_TYPE
, "host");
329 const int OSD_TYPE
= 0;
330 c
->set_type_name(OSD_TYPE
, "osd");
333 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
334 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
335 c
->set_item_name(rootno
, "default");
337 const string
HOST0("host0");
339 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
340 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
341 c
->set_item_name(host0
, HOST0
);
343 const string
HOST1("host1");
345 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
346 HOST_TYPE
, 0, NULL
, NULL
, &host1
);
347 c
->set_item_name(host1
, HOST1
);
351 // fail if invalid names anywhere in loc
353 map
<string
,string
> loc
;
354 loc
["rack"] = "\001";
355 EXPECT_EQ(-EINVAL
, c
->update_item(g_ceph_context
, item
, 1.0,
356 "osd." + stringify(item
), loc
));
358 // fail if invalid item name
360 map
<string
,string
> loc
;
361 EXPECT_EQ(-EINVAL
, c
->update_item(g_ceph_context
, item
, 1.0,
364 const string
OSD0("osd.0");
365 const string
OSD1("osd.1");
366 float original_weight
= 1.0;
367 float modified_weight
= 2.0;
370 map
<string
,string
> loc
;
371 loc
["root"] = "default";
373 EXPECT_GE(0.0, c
->get_item_weightf(host0
));
374 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, original_weight
,
377 // updating nothing changes nothing
378 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
379 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
380 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
381 EXPECT_EQ(0, c
->update_item(g_ceph_context
, item
, original_weight
,
383 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
384 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
385 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
387 // update the name and weight of the item but not the location
388 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
389 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
390 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
391 EXPECT_EQ(1, c
->update_item(g_ceph_context
, item
, modified_weight
,
393 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
394 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
395 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
396 c
->set_item_name(item
, OSD0
);
397 c
->adjust_item_weightf(g_ceph_context
, item
, original_weight
);
399 // update the name and weight of the item and change its location
400 map
<string
,string
> other_loc
;
401 other_loc
["root"] = "default";
402 other_loc
["host"] = HOST1
;
404 EXPECT_EQ(OSD0
, c
->get_item_name(item
));
405 EXPECT_EQ(original_weight
, c
->get_item_weightf(item
));
406 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
407 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, other_loc
, &weight
));
408 EXPECT_EQ(1, c
->update_item(g_ceph_context
, item
, modified_weight
,
410 EXPECT_EQ(OSD1
, c
->get_item_name(item
));
411 EXPECT_EQ(modified_weight
, c
->get_item_weightf(item
));
412 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item
, loc
, &weight
));
413 EXPECT_TRUE(c
->check_item_loc(g_ceph_context
, item
, other_loc
, &weight
));
416 TEST(CrushWrapper
, adjust_item_weight
) {
417 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
419 const int ROOT_TYPE
= 2;
420 c
->set_type_name(ROOT_TYPE
, "root");
421 const int HOST_TYPE
= 1;
422 c
->set_type_name(HOST_TYPE
, "host");
423 const int OSD_TYPE
= 0;
424 c
->set_type_name(OSD_TYPE
, "osd");
427 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
428 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
429 c
->set_item_name(rootno
, "default");
431 const string
HOST0("host0");
433 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
434 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
435 c
->set_item_name(host0
, HOST0
);
437 const string
FAKE("fake");
439 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
440 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
441 c
->set_item_name(hostfake
, FAKE
);
445 // construct crush map
448 map
<string
,string
> loc
;
449 loc
["host"] = "host0";
450 float host_weight
= 2.0;
454 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
455 "osd." + stringify(item
), loc
));
457 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
458 "osd." + stringify(item
), loc
));
460 bucket_id
= c
->get_item_id("host0");
461 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
462 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
464 map
<string
,string
> bloc
;
465 bloc
["root"] = "default";
466 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, host0
, host_weight
,
471 map
<string
,string
> loc
;
472 loc
["host"] = "fake";
473 float host_weight
= 2.0;
477 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
478 "osd." + stringify(item
), loc
));
480 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
481 "osd." + stringify(item
), loc
));
483 bucket_id
= c
->get_item_id("fake");
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(g_ceph_context
, hostfake
, host_weight
,
496 // default --> host0 --> osd.0 1.0
500 // +-> fake --> osd.0 1.0
504 // Trying to adjust osd.0 weight to 2.0 in all buckets
505 // Trying to adjust osd.1 weight to 2.0 in host=fake
507 // So the crush map will be:
509 // default --> host0 --> osd.0 2.0
513 // +-> fake --> osd.0 2.0
518 float original_weight
= 1.0;
519 float modified_weight
= 2.0;
520 map
<string
,string
> loc_one
, loc_two
;
521 loc_one
["host"] = "host0";
522 loc_two
["host"] = "fake";
525 EXPECT_EQ(2, c
->adjust_item_weightf(g_ceph_context
, item
, modified_weight
));
526 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
527 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
530 EXPECT_EQ(1, c
->adjust_item_weightf_in_loc(g_ceph_context
, item
, modified_weight
, loc_two
));
531 EXPECT_EQ(original_weight
, c
->get_item_weightf_in_loc(item
, loc_one
));
532 EXPECT_EQ(modified_weight
, c
->get_item_weightf_in_loc(item
, loc_two
));
535 TEST(CrushWrapper
, adjust_subtree_weight
) {
536 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
538 const int ROOT_TYPE
= 2;
539 c
->set_type_name(ROOT_TYPE
, "root");
540 const int HOST_TYPE
= 1;
541 c
->set_type_name(HOST_TYPE
, "host");
542 const int OSD_TYPE
= 0;
543 c
->set_type_name(OSD_TYPE
, "osd");
546 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
547 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
548 c
->set_item_name(rootno
, "default");
550 const string
HOST0("host0");
552 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
553 HOST_TYPE
, 0, NULL
, NULL
, &host0
);
554 c
->set_item_name(host0
, HOST0
);
556 const string
FAKE("fake");
558 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
559 HOST_TYPE
, 0, NULL
, NULL
, &hostfake
);
560 c
->set_item_name(hostfake
, FAKE
);
564 // construct crush map
567 map
<string
,string
> loc
;
568 loc
["host"] = "host0";
569 float host_weight
= 2.0;
573 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
574 "osd." + stringify(item
), loc
));
576 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
577 "osd." + stringify(item
), loc
));
579 bucket_id
= c
->get_item_id("host0");
580 EXPECT_EQ(true, c
->bucket_exists(bucket_id
));
581 EXPECT_EQ(host_weight
, c
->get_bucket_weightf(bucket_id
));
583 map
<string
,string
> bloc
;
584 bloc
["root"] = "default";
585 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, host0
, host_weight
,
590 map
<string
,string
> loc
;
591 loc
["host"] = "fake";
592 float host_weight
= 2.0;
596 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
597 "osd." + stringify(item
), loc
));
599 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
600 "osd." + stringify(item
), loc
));
602 bucket_id
= c
->get_item_id("fake");
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(g_ceph_context
, hostfake
, host_weight
,
612 //cout << "--------before---------" << std::endl;
613 //c->dump_tree(&cout, NULL);
614 ASSERT_EQ(c
->get_bucket_weight(host0
), 131072);
615 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144);
617 int r
= c
->adjust_subtree_weightf(g_ceph_context
, host0
, 2.0);
618 ASSERT_EQ(r
, 2); // 2 items changed
620 //cout << "--------after---------" << std::endl;
621 //c->dump_tree(&cout, NULL);
623 ASSERT_EQ(c
->get_bucket_weight(host0
), 262144);
624 ASSERT_EQ(c
->get_item_weight(host0
), 262144);
625 ASSERT_EQ(c
->get_bucket_weight(rootno
), 262144 + 131072);
628 TEST(CrushWrapper
, insert_item
) {
629 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
631 const int ROOT_TYPE
= 2;
632 c
->set_type_name(ROOT_TYPE
, "root");
633 const int HOST_TYPE
= 1;
634 c
->set_type_name(HOST_TYPE
, "host");
635 const int OSD_TYPE
= 0;
636 c
->set_type_name(OSD_TYPE
, "osd");
639 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
640 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
641 c
->set_item_name(rootno
, "default");
645 // invalid names anywhere in loc trigger an error
647 map
<string
,string
> loc
;
648 loc
["host"] = "\001";
649 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
650 "osd." + stringify(item
), loc
));
653 // insert an item in an existing bucket
655 map
<string
,string
> loc
;
656 loc
["root"] = "default";
659 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
660 "osd." + stringify(item
), loc
));
661 int another_item
= item
+ 1;
662 EXPECT_EQ(-EEXIST
, c
->insert_item(g_ceph_context
, another_item
, 1.0,
663 "osd." + stringify(item
), loc
));
665 // implicit creation of a bucket
667 string name
= "NAME";
668 map
<string
,string
> loc
;
669 loc
["root"] = "default";
673 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
674 "osd." + stringify(item
), loc
));
676 // adding to an existing item name that is not associated with a bucket
678 string name
= "ITEM_WITHOUT_BUCKET";
679 map
<string
,string
> loc
;
680 loc
["root"] = "default";
683 c
->set_item_name(item
, name
);
686 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
687 "osd." + stringify(item
), loc
));
692 // default --> host0 --> item
694 // Trying to insert the same item higher in the hirarchy will fail
695 // because it would create a loop.
697 // default --> host0 --> item
704 map
<string
,string
> loc
;
705 loc
["root"] = "default";
706 loc
["host"] = "host0";
708 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
709 "osd." + stringify(item
), loc
));
712 map
<string
,string
> loc
;
713 loc
["root"] = "default";
715 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
716 "osd." + stringify(item
), loc
));
724 // Trying to insert default under host0 must fail
725 // because it would create a loop.
727 // default --> host0 --> default
730 map
<string
,string
> loc
;
731 loc
["host"] = "host0";
733 EXPECT_EQ(-ELOOP
, c
->insert_item(g_ceph_context
, rootno
, 1.0,
736 // fail when mapping a bucket to the wrong type
738 // create an OSD bucket
740 int r
= c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
741 10, 0, NULL
, NULL
, &osdno
);
743 c
->set_item_name(osdno
, "myosd");
744 map
<string
,string
> loc
;
745 loc
["root"] = "default";
746 // wrongfully pretend the osd is of type host
747 loc
["host"] = "myosd";
750 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
751 "osd." + stringify(item
), loc
));
753 // fail when no location
755 map
<string
,string
> loc
;
757 EXPECT_EQ(-EINVAL
, c
->insert_item(g_ceph_context
, item
, 1.0,
758 "osd." + stringify(item
), loc
));
762 TEST(CrushWrapper
, remove_item
) {
763 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
765 const int ROOT_TYPE
= 2;
766 c
->set_type_name(ROOT_TYPE
, "root");
767 const int HOST_TYPE
= 1;
768 c
->set_type_name(HOST_TYPE
, "host");
769 const int OSD_TYPE
= 0;
770 c
->set_type_name(OSD_TYPE
, "osd");
774 ASSERT_EQ(0, c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
775 ROOT_TYPE
, 0, NULL
, NULL
, &root
));
776 c
->set_item_name(root
, "root0");
781 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
782 HOST_TYPE
, 0, NULL
, NULL
, &host
);
783 c
->set_item_name(host
, "host0");
786 const int num_osd
= 12;
788 map
<string
, string
> loc
= {{"root", "root0"},
791 for (int item
= 0; item
< num_osd
; item
++) {
792 ASSERT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
793 name
+ to_string(item
), loc
));
796 const int item_to_remove
= num_osd
/ 2;
797 map
<string
, string
> loc
;
798 loc
.insert(c
->get_immediate_parent(item_to_remove
));
799 ASSERT_EQ(0, c
->remove_item(g_ceph_context
, item_to_remove
, true));
801 EXPECT_FALSE(c
->check_item_loc(g_ceph_context
, item_to_remove
, loc
, &weight
));
804 TEST(CrushWrapper
, item_bucket_names
) {
805 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
807 string name
= "NAME";
808 EXPECT_EQ(-EINVAL
, c
->set_item_name(index
, "\001"));
809 EXPECT_EQ(0, c
->set_item_name(index
, name
));
810 EXPECT_TRUE(c
->name_exists(name
));
811 EXPECT_TRUE(c
->item_exists(index
));
812 EXPECT_EQ(index
, c
->get_item_id(name
));
813 EXPECT_EQ(name
, c
->get_item_name(index
));
816 TEST(CrushWrapper
, bucket_types
) {
817 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
819 string name
= "NAME";
820 c
->set_type_name(index
, name
);
821 EXPECT_EQ(1, c
->get_num_type_names());
822 EXPECT_EQ(index
, c
->get_type_id(name
));
823 EXPECT_EQ(name
, c
->get_type_name(index
));
826 TEST(CrushWrapper
, is_valid_crush_name
) {
827 EXPECT_TRUE(CrushWrapper::is_valid_crush_name("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012456789-_"));
828 EXPECT_FALSE(CrushWrapper::is_valid_crush_name(""));
829 EXPECT_FALSE(CrushWrapper::is_valid_crush_name("\001"));
832 TEST(CrushWrapper
, is_valid_crush_loc
) {
833 map
<string
,string
> loc
;
834 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
835 loc
["good"] = "better";
836 EXPECT_TRUE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
838 map
<string
,string
> loc
;
839 loc
["\005"] = "default";
840 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
843 map
<string
,string
> loc
;
844 loc
["host"] = "\003";
845 EXPECT_FALSE(CrushWrapper::is_valid_crush_loc(g_ceph_context
, loc
));
849 TEST(CrushWrapper
, dump_rules
) {
850 std::unique_ptr
<CrushWrapper
> c(new CrushWrapper
);
852 const int ROOT_TYPE
= 1;
853 c
->set_type_name(ROOT_TYPE
, "root");
854 const int OSD_TYPE
= 0;
855 c
->set_type_name(OSD_TYPE
, "osd");
857 string
failure_domain_type("osd");
858 string
root_name("default");
860 c
->add_bucket(0, CRUSH_BUCKET_STRAW
, CRUSH_HASH_RJENKINS1
,
861 ROOT_TYPE
, 0, NULL
, NULL
, &rootno
);
862 c
->set_item_name(rootno
, root_name
);
866 pair
<string
,string
> loc
;
868 loc
= c
->get_immediate_parent(item
, &ret
);
869 EXPECT_EQ(-ENOENT
, ret
);
872 map
<string
,string
> loc
;
873 loc
["root"] = root_name
;
875 EXPECT_EQ(0, c
->insert_item(g_ceph_context
, item
, 1.0,
879 // no rule by default
881 Formatter
*f
= Formatter::create("json-pretty");
882 f
->open_array_section("rules");
888 EXPECT_EQ("[]\n", ss
.str());
892 int rule
= c
->add_simple_rule(name
, root_name
, failure_domain_type
, "",
893 "firstn", pg_pool_t::TYPE_ERASURE
);
897 Formatter
*f
= Formatter::create("xml");
902 EXPECT_EQ((unsigned)0, ss
.str().find("<rule><rule_id>0</rule_id><rule_name>NAME</rule_name>"));
906 Formatter
*f
= Formatter::create("xml");
907 c
->dump_rule(rule
, f
);
911 EXPECT_EQ((unsigned)0, ss
.str().find("<rule><rule_id>0</rule_id><rule_name>NAME</rule_name>"));
912 EXPECT_NE(string::npos
,
913 ss
.str().find("<item_name>default</item_name></step>"));
917 c
->get_rule_weight_osd_map(0, &wm
);
918 ASSERT_TRUE(wm
.size() == 1);
919 ASSERT_TRUE(wm
[0] == 1.0);
922 TEST(CrushWrapper
, distance
) {
925 c
.set_type_name(1, "host");
926 c
.set_type_name(2, "rack");
927 c
.set_type_name(3, "root");
929 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW
,
930 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
934 c
.set_item_name(bno
, "default");
936 c
.set_max_devices(10);
938 //JSONFormatter jf(true);
940 map
<string
,string
> loc
;
943 loc
["root"] = "default";
944 c
.insert_item(g_ceph_context
, 0, 1, "osd.0", loc
);
949 loc
["root"] = "default";
950 c
.insert_item(g_ceph_context
, 1, 1, "osd.1", loc
);
955 loc
["root"] = "default";
956 c
.insert_item(g_ceph_context
, 2, 1, "osd.2", loc
);
961 loc
["root"] = "default";
962 c
.insert_item(g_ceph_context
, 3, 1, "osd.3", loc
);
964 vector
<pair
<string
,string
> > ol
;
965 c
.get_full_location_ordered(3, ol
);
966 ASSERT_EQ(3u, ol
.size());
967 ASSERT_EQ(make_pair(string("host"),string("b2")), ol
[0]);
968 ASSERT_EQ(make_pair(string("rack"),string("b")), ol
[1]);
969 ASSERT_EQ(make_pair(string("root"),string("default")), ol
[2]);
974 multimap
<string
,string
> p
;
975 p
.insert(make_pair("host","b2"));
976 p
.insert(make_pair("rack","b"));
977 p
.insert(make_pair("root","default"));
978 ASSERT_EQ(3, c
.get_common_ancestor_distance(g_ceph_context
, 0, p
));
979 ASSERT_EQ(3, c
.get_common_ancestor_distance(g_ceph_context
, 1, p
));
980 ASSERT_EQ(2, c
.get_common_ancestor_distance(g_ceph_context
, 2, p
));
981 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 3, p
));
982 ASSERT_EQ(-ENOENT
, c
.get_common_ancestor_distance(g_ceph_context
, 123, p
));
984 // make sure a "multipath" location will reflect a minimal
985 // distance for both paths
986 p
.insert(make_pair("host","b1"));
987 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 2, p
));
988 ASSERT_EQ(1, c
.get_common_ancestor_distance(g_ceph_context
, 3, p
));
991 TEST(CrushWrapper
, choose_args_compat
) {
994 c
.set_type_name(1, "host");
995 c
.set_type_name(2, "rack");
996 c
.set_type_name(3, "root");
1000 map
<string
,string
> loc
;
1002 loc
["rack"] = "r11";
1003 loc
["root"] = "default";
1005 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1008 loc
["rack"] = "r12";
1009 loc
["root"] = "default";
1011 c
.insert_item(g_ceph_context
, item
, weight
, "osd.2", loc
);
1013 assert(c
.add_simple_rule("rule1", "r11", "host", "",
1014 "firstn", pg_pool_t::TYPE_ERASURE
) >= 0);
1016 int id
= c
.get_item_id("b1");
1018 __u32 weights
= 666 * 0x10000;
1019 crush_weight_set weight_set
;
1020 weight_set
.size
= 1;
1021 weight_set
.weights
= &weights
;
1022 int maxbuckets
= c
.get_max_buckets();
1023 assert(maxbuckets
> 0);
1024 crush_choose_arg choose_args
[maxbuckets
];
1025 memset(choose_args
, '\0', sizeof(crush_choose_arg
) * maxbuckets
);
1026 choose_args
[-1-id
].ids_size
= 0;
1027 choose_args
[-1-id
].weight_set_positions
= 1;
1028 choose_args
[-1-id
].weight_set
= &weight_set
;
1029 crush_choose_arg_map arg_map
;
1030 arg_map
.size
= c
.get_max_buckets();
1031 arg_map
.args
= choose_args
;
1033 uint64_t features
= CEPH_FEATURE_CRUSH_TUNABLES5
|CEPH_FEATURE_INCARNATION_2
;
1034 int64_t caid
= CrushWrapper::DEFAULT_CHOOSE_ARGS
;
1036 // if the client is capable, encode choose_args
1038 c
.choose_args
[caid
] = arg_map
;
1040 c
.encode(bl
, features
|CEPH_FEATURE_CRUSH_CHOOSE_ARGS
);
1041 bufferlist::iterator
i(bl
.begin());
1044 ASSERT_EQ(1u, c_new
.choose_args
.size());
1045 ASSERT_EQ(1u, c_new
.choose_args
[caid
].args
[-1-id
].weight_set_positions
);
1046 ASSERT_EQ(weights
, c_new
.choose_args
[caid
].args
[-1-id
].weight_set
[0].weights
[0]);
1047 ASSERT_EQ(weight
, c_new
.get_bucket_item_weightf(id
, 0));
1050 // if the client is not compatible, copy choose_arg in the weights
1052 c
.choose_args
[caid
] = arg_map
;
1054 c
.encode(bl
, features
);
1055 c
.choose_args
.clear();
1056 bufferlist::iterator
i(bl
.begin());
1059 ASSERT_EQ(0u, c_new
.choose_args
.size());
1060 ASSERT_EQ((int)weights
, c_new
.get_bucket_item_weight(id
, 0));
1064 TEST(CrushWrapper
, remove_root
) {
1067 c
.set_type_name(1, "host");
1068 c
.set_type_name(2, "rack");
1069 c
.set_type_name(3, "root");
1073 map
<string
,string
> loc
;
1075 loc
["rack"] = "r11";
1076 loc
["root"] = "default";
1078 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1081 loc
["rack"] = "r12";
1082 loc
["root"] = "default";
1083 c
.insert_item(g_ceph_context
, item
, weight
, "osd.2", loc
);
1085 assert(c
.add_simple_rule("rule1", "r11", "host", "",
1086 "firstn", pg_pool_t::TYPE_ERASURE
) >= 0);
1087 ASSERT_TRUE(c
.name_exists("default"));
1088 ASSERT_TRUE(c
.name_exists("r11"));
1089 ASSERT_TRUE(c
.name_exists("r12"));
1090 ASSERT_EQ(c
.remove_root(c
.get_item_id("default")), 0);
1091 ASSERT_FALSE(c
.name_exists("default"));
1092 ASSERT_FALSE(c
.name_exists("r11"));
1093 ASSERT_FALSE(c
.name_exists("r12"));
1096 TEST(CrushWrapper
, trim_roots_with_class
) {
1099 c
.set_type_name(1, "root");
1102 map
<string
,string
> loc
;
1103 loc
["root"] = "default";
1106 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1107 int cl
= c
.get_or_create_class_id("ssd");
1108 c
.class_map
[item
] = cl
;
1111 int root_id
= c
.get_item_id("default");
1113 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1114 map
<int,map
<int,vector
<int>>> cmap_item_weight
; // cargs -> bno -> weights
1115 set
<int32_t> used_ids
;
1117 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, old_class_bucket
, used_ids
,
1118 &clone_id
, &cmap_item_weight
), 0);
1120 ASSERT_TRUE(c
.name_exists("default"));
1121 ASSERT_TRUE(c
.name_exists("default~ssd"));
1122 c
.trim_roots_with_class();
1123 ASSERT_TRUE(c
.name_exists("default"));
1124 ASSERT_FALSE(c
.name_exists("default~ssd"));
1127 TEST(CrushWrapper
, device_class_clone
) {
1130 c
.set_type_name(1, "host");
1131 c
.set_type_name(2, "root");
1133 map
<string
,string
> loc
;
1135 loc
["root"] = "default";
1139 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1140 int cl
= c
.get_or_create_class_id("ssd");
1141 c
.class_map
[item
] = cl
;
1143 int item_no_class
= 2;
1144 c
.insert_item(g_ceph_context
, item_no_class
, weight
, "osd.2", loc
);
1146 c
.reweight(g_ceph_context
);
1148 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1149 map
<int,map
<int,vector
<int>>> cmap_item_weight
; // cargs -> bno -> weights
1150 set
<int32_t> used_ids
;
1151 int root_id
= c
.get_item_id("default");
1153 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, old_class_bucket
, used_ids
,
1154 &clone_id
, &cmap_item_weight
), 0);
1155 ASSERT_TRUE(c
.name_exists("default~ssd"));
1156 ASSERT_EQ(clone_id
, c
.get_item_id("default~ssd"));
1157 ASSERT_TRUE(c
.subtree_contains(clone_id
, item
));
1158 ASSERT_FALSE(c
.subtree_contains(clone_id
, item_no_class
));
1159 ASSERT_TRUE(c
.subtree_contains(root_id
, item_no_class
));
1160 ASSERT_EQ(c
.get_item_weightf(root_id
), 2);
1161 ASSERT_EQ(c
.get_item_weightf(clone_id
), 1);
1162 // cloning again does nothing and returns the existing one
1164 ASSERT_EQ(c
.device_class_clone(root_id
, cl
, old_class_bucket
, used_ids
,
1165 &other_clone_id
, &cmap_item_weight
), 0);
1166 ASSERT_EQ(clone_id
, other_clone_id
);
1167 // invalid arguments
1168 ASSERT_EQ(c
.device_class_clone(12345, cl
, old_class_bucket
, used_ids
,
1169 &other_clone_id
, &cmap_item_weight
), -ECHILD
);
1170 ASSERT_EQ(c
.device_class_clone(root_id
, 12345, old_class_bucket
, used_ids
,
1171 &other_clone_id
, &cmap_item_weight
), -EBADF
);
1174 TEST(CrushWrapper
, split_id_class
) {
1177 c
.set_type_name(1, "root");
1180 map
<string
,string
> loc
;
1181 loc
["root"] = "default";
1184 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1185 int class_id
= c
.get_or_create_class_id("ssd");
1186 c
.class_map
[item
] = class_id
;
1188 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1189 map
<int,map
<int,vector
<int>>> cmap_item_weight
; // cargs -> bno -> weights
1190 set
<int32_t> used_ids
;
1191 int item_id
= c
.get_item_id("default");
1193 ASSERT_EQ(c
.device_class_clone(item_id
, class_id
, old_class_bucket
, used_ids
,
1194 &clone_id
, &cmap_item_weight
), 0);
1195 int retrieved_item_id
;
1196 int retrieved_class_id
;
1197 ASSERT_EQ(c
.split_id_class(clone_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1198 ASSERT_EQ(item_id
, retrieved_item_id
);
1199 ASSERT_EQ(class_id
, retrieved_class_id
);
1201 ASSERT_EQ(c
.split_id_class(item_id
, &retrieved_item_id
, &retrieved_class_id
), 0);
1202 ASSERT_EQ(item_id
, retrieved_item_id
);
1203 ASSERT_EQ(-1, retrieved_class_id
);
1206 TEST(CrushWrapper
, populate_classes
) {
1209 c
.set_type_name(1, "root");
1212 map
<string
,string
> loc
;
1213 loc
["root"] = "default";
1216 c
.insert_item(g_ceph_context
, item
, weight
, "osd.1", loc
);
1217 int class_id
= c
.get_or_create_class_id("ssd");
1218 c
.class_map
[item
] = class_id
;
1220 map
<int32_t, map
<int32_t, int32_t>> old_class_bucket
;
1221 ASSERT_EQ(c
.populate_classes(old_class_bucket
), 0);
1223 ASSERT_TRUE(c
.name_exists("default~ssd"));
1225 old_class_bucket
= c
.class_bucket
;
1226 ASSERT_EQ(c
.populate_classes(old_class_bucket
), 0);
1227 ASSERT_EQ(old_class_bucket
, c
.class_bucket
);
1230 TEST(CrushWrapper
, remove_class_name
) {
1234 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1235 ASSERT_GE(0, c
.get_or_create_class_id("ssd"));
1236 ASSERT_EQ(0, c
.remove_class_name("ssd"));
1237 ASSERT_EQ(-ENOENT
, c
.remove_class_name("ssd"));
1240 TEST(CrushWrapper
, try_remap_rule
) {
1241 // build a simple 2 level map
1244 c
.set_type_name(0, "osd");
1245 c
.set_type_name(1, "host");
1246 c
.set_type_name(2, "rack");
1247 c
.set_type_name(3, "root");
1249 int r
= c
.add_bucket(0, CRUSH_BUCKET_STRAW2
,
1250 CRUSH_HASH_DEFAULT
, 3, 0, NULL
,
1254 c
.set_item_name(bno
, "default");
1256 c
.set_max_devices(20);
1258 //JSONFormatter jf(true);
1260 map
<string
,string
> loc
;
1261 loc
["host"] = "foo";
1263 loc
["root"] = "default";
1264 c
.insert_item(g_ceph_context
, 0, 1, "osd.0", loc
);
1265 c
.insert_item(g_ceph_context
, 1, 1, "osd.1", loc
);
1266 c
.insert_item(g_ceph_context
, 2, 1, "osd.2", loc
);
1269 loc
["host"] = "bar";
1271 loc
["root"] = "default";
1272 c
.insert_item(g_ceph_context
, 3, 1, "osd.3", loc
);
1273 c
.insert_item(g_ceph_context
, 4, 1, "osd.4", loc
);
1274 c
.insert_item(g_ceph_context
, 5, 1, "osd.5", loc
);
1277 loc
["host"] = "baz";
1279 loc
["root"] = "default";
1280 c
.insert_item(g_ceph_context
, 6, 1, "osd.6", loc
);
1281 c
.insert_item(g_ceph_context
, 7, 1, "osd.7", loc
);
1282 c
.insert_item(g_ceph_context
, 8, 1, "osd.8", loc
);
1285 loc
["host"] = "qux";
1287 loc
["root"] = "default";
1288 c
.insert_item(g_ceph_context
, 9, 1, "osd.9", loc
);
1289 c
.insert_item(g_ceph_context
, 10, 1, "osd.10", loc
);
1290 c
.insert_item(g_ceph_context
, 11, 1, "osd.11", loc
);
1294 loc
["host"] = "bif";
1296 loc
["root"] = "default";
1297 c
.insert_item(g_ceph_context
, 12, 1, "osd.12", loc
);
1298 c
.insert_item(g_ceph_context
, 13, 1, "osd.13", loc
);
1299 c
.insert_item(g_ceph_context
, 14, 1, "osd.14", loc
);
1303 loc
["host"] = "pop";
1305 loc
["root"] = "default";
1306 c
.insert_item(g_ceph_context
, 15, 1, "osd.15", loc
);
1307 c
.insert_item(g_ceph_context
, 16, 1, "osd.16", loc
);
1308 c
.insert_item(g_ceph_context
, 17, 1, "osd.17", loc
);
1318 // take + choose device + emit
1320 cout
<< "take + choose + emit" << std::endl
;
1322 int rule
= c
.add_simple_rule("one", "default", "osd", "",
1326 vector
<int> orig
= { 0, 3, 9 };
1327 set
<int> overfull
= { 3 };
1328 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1330 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1331 overfull
, underfull
,
1333 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1335 ASSERT_EQ(3u, out
.size());
1336 ASSERT_EQ(0, out
[0]);
1337 ASSERT_EQ(2, out
[1]);
1338 ASSERT_EQ(9, out
[2]);
1340 // make sure we cope with dups between underfull and future values in orig
1341 underfull
= {9, 0, 2, 5};
1344 r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1345 overfull
, underfull
,
1347 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1349 ASSERT_EQ(3u, out
.size());
1350 ASSERT_EQ(1, out
[0]);
1351 ASSERT_EQ(0, out
[1]);
1352 ASSERT_EQ(9, out
[2]);
1357 cout
<< "take + chooseleaf + emit" << std::endl
;
1359 int rule
= c
.add_simple_rule("two", "default", "host", "",
1363 vector
<int> orig
= { 0, 3, 9 };
1364 set
<int> overfull
= { 3 };
1365 vector
<int> underfull
= { 0, 2, 5, 8, 11 };
1367 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1368 overfull
, underfull
,
1370 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1372 ASSERT_EQ(3u, out
.size());
1373 ASSERT_EQ(0, out
[0]);
1374 ASSERT_EQ(5, out
[1]);
1375 ASSERT_EQ(9, out
[2]);
1380 cout
<< "take + choose + choose + choose + emit" << std::endl
;
1381 int rule
= c
.add_rule(2, 5, 0, 1, 10);
1383 c
.set_rule_step_take(rule
, 0, bno
);
1384 c
.set_rule_step_choose_indep(rule
, 1, 2, 2);
1385 c
.set_rule_step_choose_indep(rule
, 2, 2, 1);
1386 c
.set_rule_step_choose_indep(rule
, 3, 1, 0);
1387 c
.set_rule_step_emit(rule
, 4);
1389 vector
<int> orig
= { 0, 3, 16, 12 };
1390 set
<int> overfull
= { 3, 12 };
1391 vector
<int> underfull
= { 6, 7, 9, 3, 0, 1, 15, 16, 13, 2, 5, 8, 11 };
1393 int r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1394 overfull
, underfull
,
1396 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1398 ASSERT_EQ(4u, out
.size());
1399 ASSERT_EQ(0, out
[0]);
1400 ASSERT_EQ(5, out
[1]);
1401 ASSERT_EQ(16, out
[2]);
1402 ASSERT_EQ(13, out
[3]);
1406 r
= c
.try_remap_rule(g_ceph_context
, rule
, 3,
1407 overfull
, underfull
,
1409 cout
<< orig
<< " -> r = " << (int)r
<< " out " << out
<< std::endl
;
1411 ASSERT_EQ(3u, out
.size());
1412 ASSERT_EQ(0, out
[0]);
1413 ASSERT_EQ(5, out
[1]);
1414 ASSERT_EQ(16, out
[2]);
1418 int main(int argc
, char **argv
) {
1419 vector
<const char*> args
;
1420 argv_to_vec(argc
, (const char **)argv
, args
);
1423 vector
<const char*> def_args
;
1424 def_args
.push_back("--debug-crush=0");
1425 auto cct
= global_init(&def_args
, args
, CEPH_ENTITY_TYPE_CLIENT
,
1426 CODE_ENVIRONMENT_UTILITY
, 0);
1427 common_init_finish(g_ceph_context
);
1428 ::testing::InitGoogleTest(&argc
, argv
);
1429 return RUN_ALL_TESTS();
1432 // compile-command: "cd ../../../build ; make -j4 unittest_crush_wrapper && valgrind --tool=memcheck bin/unittest_crush_wrapper"