]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/objectstore/store_test.cc
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / test / objectstore / store_test.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include <glob.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <iostream>
19 #include <memory>
20 #include <time.h>
21 #include <sys/mount.h>
22 #include <boost/random/mersenne_twister.hpp>
23 #include <boost/random/uniform_int.hpp>
24 #include <boost/random/binomial_distribution.hpp>
25 #include <fmt/format.h>
26 #include <gtest/gtest.h>
27
28 #include "os/ObjectStore.h"
29 #if defined(WITH_BLUESTORE)
30 #include "os/bluestore/BlueStore.h"
31 #include "os/bluestore/BlueFS.h"
32 #endif
33 #include "include/Context.h"
34 #include "common/buffer_instrumentation.h"
35 #include "common/ceph_argparse.h"
36 #include "common/admin_socket.h"
37 #include "global/global_init.h"
38 #include "common/ceph_mutex.h"
39 #include "common/Cond.h"
40 #include "common/errno.h"
41 #include "common/options.h" // for the size literals
42 #include "common/pretty_binary.h"
43 #include "include/stringify.h"
44 #include "include/coredumpctl.h"
45 #include "include/unordered_map.h"
46 #include "os/kv.h"
47 #include "store_test_fixture.h"
48
49
50 using namespace std;
51 using namespace std::placeholders;
52
53 typedef boost::mt11213b gen_type;
54
55 const uint64_t DEF_STORE_TEST_BLOCKDEV_SIZE = 10240000000;
56 #define dout_context g_ceph_context
57
58 bool smr = false;
59
60 static bool bl_eq(bufferlist& expected, bufferlist& actual)
61 {
62 if (expected.contents_equal(actual))
63 return true;
64
65 unsigned first = 0;
66 if(expected.length() != actual.length()) {
67 cout << "--- buffer lengths mismatch " << std::hex
68 << "expected 0x" << expected.length() << " != actual 0x"
69 << actual.length() << std::dec << std::endl;
70 derr << "--- buffer lengths mismatch " << std::hex
71 << "expected 0x" << expected.length() << " != actual 0x"
72 << actual.length() << std::dec << dendl;
73 }
74 auto len = std::min(expected.length(), actual.length());
75 while ( first<len && expected[first] == actual[first])
76 ++first;
77 unsigned last = len;
78 while (last > 0 && expected[last-1] == actual[last-1])
79 --last;
80 if(len > 0) {
81 cout << "--- buffer mismatch between offset 0x" << std::hex << first
82 << " and 0x" << last << ", total 0x" << len << std::dec
83 << std::endl;
84 derr << "--- buffer mismatch between offset 0x" << std::hex << first
85 << " and 0x" << last << ", total 0x" << len << std::dec
86 << dendl;
87 cout << "--- expected:\n";
88 expected.hexdump(cout);
89 cout << "--- actual:\n";
90 actual.hexdump(cout);
91 }
92 return false;
93 }
94
95
96
97 template <typename T>
98 int queue_transaction(
99 T &store,
100 ObjectStore::CollectionHandle ch,
101 ObjectStore::Transaction &&t) {
102 if (rand() % 2) {
103 ObjectStore::Transaction t2;
104 t2.append(t);
105 return store->queue_transaction(ch, std::move(t2));
106 } else {
107 return store->queue_transaction(ch, std::move(t));
108 }
109 }
110
111 template <typename T>
112 int collection_list(T &store, ObjectStore::CollectionHandle &c,
113 const ghobject_t& start, const ghobject_t& end, int max,
114 vector<ghobject_t> *ls, ghobject_t *pnext,
115 bool disable_legacy = false) {
116 if (disable_legacy || rand() % 2) {
117 return store->collection_list(c, start, end, max, ls, pnext);
118 } else {
119 return store->collection_list_legacy(c, start, end, max, ls, pnext);
120 }
121 }
122
123 bool sorted(const vector<ghobject_t> &in) {
124 ghobject_t start;
125 for (vector<ghobject_t>::const_iterator i = in.begin();
126 i != in.end();
127 ++i) {
128 if (start > *i) {
129 cout << start << " should follow " << *i << std::endl;
130 return false;
131 }
132 start = *i;
133 }
134 return true;
135 }
136
137 class StoreTest : public StoreTestFixture,
138 public ::testing::WithParamInterface<const char*> {
139 public:
140 StoreTest()
141 : StoreTestFixture(GetParam())
142 {}
143 void doCompressionTest();
144 void doSyntheticTest(
145 int num_ops,
146 uint64_t max_obj, uint64_t max_wr, uint64_t align);
147 };
148
149 class StoreTestDeferredSetup : public StoreTest {
150 void SetUp() override {
151 //do nothing
152 }
153
154 protected:
155 void DeferredSetup() {
156 StoreTest::SetUp();
157 }
158
159 public:
160 };
161
162
163 class StoreTestSpecificAUSize : public StoreTestDeferredSetup {
164
165 public:
166 typedef
167 std::function<void(
168 uint64_t num_ops,
169 uint64_t max_obj,
170 uint64_t max_wr,
171 uint64_t align)> MatrixTest;
172
173 void StartDeferred(size_t min_alloc_size) {
174 SetVal(g_conf(), "bluestore_min_alloc_size", stringify(min_alloc_size).c_str());
175 DeferredSetup();
176 }
177
178 private:
179 // bluestore matrix testing
180 uint64_t max_write = 40 * 1024;
181 uint64_t max_size = 400 * 1024;
182 uint64_t alignment = 0;
183 uint64_t num_ops = 10000;
184
185 protected:
186 string matrix_get(const char *k) {
187 if (string(k) == "max_write") {
188 return stringify(max_write);
189 } else if (string(k) == "max_size") {
190 return stringify(max_size);
191 } else if (string(k) == "alignment") {
192 return stringify(alignment);
193 } else if (string(k) == "num_ops") {
194 return stringify(num_ops);
195 } else {
196 char *buf;
197 g_conf().get_val(k, &buf, -1);
198 string v = buf;
199 free(buf);
200 return v;
201 }
202 }
203
204 void matrix_set(const char *k, const char *v) {
205 if (string(k) == "max_write") {
206 max_write = atoll(v);
207 } else if (string(k) == "max_size") {
208 max_size = atoll(v);
209 } else if (string(k) == "alignment") {
210 alignment = atoll(v);
211 } else if (string(k) == "num_ops") {
212 num_ops = atoll(v);
213 } else {
214 SetVal(g_conf(), k, v);
215 }
216 }
217
218 void do_matrix_choose(const char *matrix[][10],
219 int i, int pos, int num,
220 MatrixTest fn) {
221 if (matrix[i][0]) {
222 int count;
223 for (count = 0; matrix[i][count+1]; ++count) ;
224 for (int j = 1; matrix[i][j]; ++j) {
225 matrix_set(matrix[i][0], matrix[i][j]);
226 do_matrix_choose(matrix,
227 i + 1,
228 pos * count + j - 1,
229 num * count,
230 fn);
231 }
232 } else {
233 cout << "---------------------- " << (pos + 1) << " / " << num
234 << " ----------------------" << std::endl;
235 for (unsigned k=0; matrix[k][0]; ++k) {
236 cout << " " << matrix[k][0] << " = " << matrix_get(matrix[k][0])
237 << std::endl;
238 }
239 g_ceph_context->_conf.apply_changes(nullptr);
240 fn(num_ops, max_size, max_write, alignment);
241 }
242 }
243
244 void do_matrix(const char *matrix[][10],
245 MatrixTest fn) {
246
247 if (strcmp(matrix[0][0], "bluestore_min_alloc_size") == 0) {
248 int count;
249 for (count = 0; matrix[0][count+1]; ++count) ;
250 for (size_t j = 1; matrix[0][j]; ++j) {
251 if (j > 1) {
252 TearDown();
253 }
254 StartDeferred(strtoll(matrix[0][j], NULL, 10));
255 do_matrix_choose(matrix, 1, j - 1, count, fn);
256 }
257 } else {
258 StartDeferred(0);
259 do_matrix_choose(matrix, 0, 0, 1, fn);
260 }
261 }
262
263 };
264
265 class StoreTestOmapUpgrade : public StoreTestDeferredSetup {
266 protected:
267 void StartDeferred() {
268 DeferredSetup();
269 }
270
271 public:
272 struct generator {
273 double r = 3.6;
274 double x = 0.5;
275 double operator()(){
276 double v = x;
277 x = r * x * (1 - x);
278 return v;
279 }
280 };
281
282 std::string generate_monotonic_name(uint32_t SUM, uint32_t i, double r, double x)
283 {
284 generator gen{r, x};
285 //std::cout << "r=" << r << " x=" << x << std::endl;
286 std::string s;
287 while (SUM > 1) {
288 uint32_t lo = 0;
289 uint32_t hi = 1 + gen() * 10;
290 uint32_t start = ('z' - 'a' + 1 - hi) * gen();
291 while (hi - lo > 0) {
292 uint32_t mid = (lo + hi + 1 + (SUM&1)) / 2; // round up or down, depending on SUM
293 // std::cout << "SUM=" << SUM << " x=" << gen.x << std::endl;
294 uint32_t mid_val = gen() * (SUM - 1) + 1;
295 // LEFT = lo .. mid - 1
296 // RIGHT = mid .. hi
297 // std::cout << "lo=" << lo << " hi=" << hi << " mid=" << mid
298 // << " SUM=" << SUM << " i=" << i << " x=" << gen.x << " mid_val=" << mid_val << std::endl;
299 if (i < mid_val) {
300 hi = mid - 1;
301 SUM = mid_val;
302 } else {
303 lo = mid;
304 SUM = SUM - mid_val;
305 i = i - mid_val;
306 }
307 }
308 //std::cout << "lo=" << lo << " hi=" << hi
309 // << " SUM=" << SUM << " i=" << i << std::endl;
310
311 s.push_back('a' + lo + start); // to keep alphabetic order
312 uint32_t cnt = gen() * 8;
313 for (uint32_t j = 0; j < cnt; j++) {
314 s.push_back('a' + ('z' - 'a' + 1) * gen());
315 }
316 s.push_back('.');
317 }
318 return s;
319 }
320
321 std::string gen_string(size_t size, generator& gen) {
322 std::string s;
323 for (size_t i = 0; i < size; i++) {
324 s.push_back('a' + ('z' - 'a' + 1 ) * gen());
325 }
326 return s;
327 }
328
329 void make_omap_data(size_t object_count,
330 int64_t poolid,
331 coll_t cid) {
332 int r;
333 ObjectStore::CollectionHandle ch = store->open_collection(cid);
334 for (size_t o = 0; o < object_count; o++)
335 {
336 ObjectStore::Transaction t;
337 std::string oid = generate_monotonic_name(object_count, o, 3.71, 0.5);
338 ghobject_t hoid(hobject_t(oid, "", CEPH_NOSNAP, 0, poolid, ""));
339 t.touch(cid, hoid);
340 generator gen{3.85 + 0.1 * o / object_count, 1 - double(o) / object_count};
341
342 map<string, bufferlist> start_set;
343 size_t omap_count = 1 + gen() * 20;
344 bool do_omap_header = gen() > 0.5;
345 if (do_omap_header) {
346 bufferlist header;
347 header.append(gen_string(50, gen));
348 t.omap_setheader(cid, hoid, header);
349 }
350 for (size_t i = 0; i < omap_count; i++) {
351 std::string name = generate_monotonic_name(omap_count, i, 3.66 + 0.22 * o / object_count, 0.5);
352 bufferlist val;
353 val.append(gen_string(100, gen));
354 start_set.emplace(name, val);
355 }
356 t.omap_setkeys(cid, hoid, start_set);
357 r = queue_transaction(store, ch, std::move(t));
358 ASSERT_EQ(r, 0);
359 }
360 }
361
362 void check_omap_data(size_t object_count,
363 int64_t poolid,
364 coll_t cid) {
365 int r;
366 ObjectStore::CollectionHandle ch = store->open_collection(cid);
367
368 for (size_t o = 0; o < object_count; o++)
369 {
370 ObjectStore::Transaction t;
371 std::string oid = generate_monotonic_name(object_count, o, 3.71, 0.5);
372 ghobject_t hoid(hobject_t(oid, "", CEPH_NOSNAP, 0, poolid, ""));
373 generator gen{3.85 + 0.1 * o / object_count, 1 - double(o) / object_count};
374
375 bufferlist omap_header;
376 map<string, bufferlist> omap_set;
377 r = store->omap_get(ch, hoid, &omap_header, &omap_set);
378 ASSERT_EQ(r, 0);
379 size_t omap_count = 1 + gen() * 20;
380 bool do_omap_header = gen() > 0.5;
381 if (do_omap_header) {
382 std::string header_str = gen_string(50, gen);
383 ASSERT_EQ(header_str, omap_header.to_str());
384 }
385 auto it = omap_set.begin();
386 for (size_t i = 0; i < omap_count; i++) {
387 ASSERT_TRUE(it != omap_set.end());
388 std::string name = generate_monotonic_name(omap_count, i, 3.66 + 0.22 * o / object_count, 0.5);
389 std::string val_gen = gen_string(100, gen);
390 ASSERT_EQ(it->first, name);
391 ASSERT_EQ(it->second.to_str(), val_gen);
392 ++it;
393 }
394 }
395 }
396 };
397
398 TEST_P(StoreTest, collect_metadata) {
399 map<string,string> pm;
400 store->collect_metadata(&pm);
401 if (GetParam() == string("filestore")) {
402 ASSERT_NE(pm.count("filestore_backend"), 0u);
403 ASSERT_NE(pm.count("filestore_f_type"), 0u);
404 ASSERT_NE(pm.count("backend_filestore_partition_path"), 0u);
405 ASSERT_NE(pm.count("backend_filestore_dev_node"), 0u);
406 }
407 }
408
409 TEST_P(StoreTest, Trivial) {
410 }
411
412 TEST_P(StoreTest, TrivialRemount) {
413 int r = store->umount();
414 ASSERT_EQ(0, r);
415 r = store->mount();
416 ASSERT_EQ(0, r);
417 }
418
419 TEST_P(StoreTest, TrivialRemountFsck) {
420 if(string(GetParam()) != "bluestore")
421 return;
422 int r = store->umount();
423 ASSERT_EQ(0, r);
424 r = store->fsck(false);
425 ASSERT_EQ(0, r);
426 r = store->mount();
427 ASSERT_EQ(0, r);
428 }
429
430 TEST_P(StoreTest, SimpleRemount) {
431 coll_t cid;
432 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
433 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
434 bufferlist bl;
435 bl.append("1234512345");
436 int r;
437 auto ch = store->create_new_collection(cid);
438 {
439 cerr << "create collection + write" << std::endl;
440 ObjectStore::Transaction t;
441 t.create_collection(cid, 0);
442 t.write(cid, hoid, 0, bl.length(), bl);
443 r = queue_transaction(store, ch, std::move(t));
444 ASSERT_EQ(r, 0);
445 }
446 ch.reset();
447 r = store->umount();
448 ASSERT_EQ(0, r);
449 r = store->mount();
450 ASSERT_EQ(0, r);
451 ch = store->open_collection(cid);
452 {
453 ObjectStore::Transaction t;
454 t.write(cid, hoid2, 0, bl.length(), bl);
455 r = queue_transaction(store, ch, std::move(t));
456 ASSERT_EQ(r, 0);
457 }
458 {
459 ObjectStore::Transaction t;
460 t.remove(cid, hoid);
461 t.remove(cid, hoid2);
462 t.remove_collection(cid);
463 cerr << "remove collection" << std::endl;
464 r = queue_transaction(store, ch, std::move(t));
465 ASSERT_EQ(r, 0);
466 }
467 ch.reset();
468 r = store->umount();
469 ASSERT_EQ(0, r);
470 r = store->mount();
471 ASSERT_EQ(0, r);
472 ch = store->create_new_collection(cid);
473 {
474 ObjectStore::Transaction t;
475 t.create_collection(cid, 0);
476 r = queue_transaction(store, ch, std::move(t));
477 ASSERT_EQ(r, 0);
478 bool exists = store->exists(ch, hoid);
479 ASSERT_TRUE(!exists);
480 }
481 {
482 ObjectStore::Transaction t;
483 t.remove_collection(cid);
484 cerr << "remove collection" << std::endl;
485 r = queue_transaction(store, ch, std::move(t));
486 ASSERT_EQ(r, 0);
487 }
488 }
489
490 TEST_P(StoreTest, IORemount) {
491 coll_t cid;
492 bufferlist bl;
493 bl.append("1234512345");
494 int r;
495 auto ch = store->create_new_collection(cid);
496 {
497 cerr << "create collection + objects" << std::endl;
498 ObjectStore::Transaction t;
499 t.create_collection(cid, 0);
500 for (int n=1; n<=100; ++n) {
501 ghobject_t hoid(hobject_t(sobject_t("Object " + stringify(n), CEPH_NOSNAP)));
502 t.write(cid, hoid, 0, bl.length(), bl);
503 }
504 r = queue_transaction(store, ch, std::move(t));
505 ASSERT_EQ(r, 0);
506 }
507 // overwrites
508 {
509 cout << "overwrites" << std::endl;
510 for (int n=1; n<=100; ++n) {
511 ObjectStore::Transaction t;
512 ghobject_t hoid(hobject_t(sobject_t("Object " + stringify(n), CEPH_NOSNAP)));
513 t.write(cid, hoid, 1, bl.length(), bl);
514 r = queue_transaction(store, ch, std::move(t));
515 ASSERT_EQ(r, 0);
516 }
517 }
518 ch.reset();
519 r = store->umount();
520 ASSERT_EQ(0, r);
521 r = store->mount();
522 ASSERT_EQ(0, r);
523 {
524 ObjectStore::Transaction t;
525 for (int n=1; n<=100; ++n) {
526 ghobject_t hoid(hobject_t(sobject_t("Object " + stringify(n), CEPH_NOSNAP)));
527 t.remove(cid, hoid);
528 }
529 t.remove_collection(cid);
530 auto ch = store->open_collection(cid);
531 r = queue_transaction(store, ch, std::move(t));
532 ASSERT_EQ(r, 0);
533 }
534 }
535
536 TEST_P(StoreTest, UnprintableCharsName) {
537 coll_t cid;
538 string name = "funnychars_";
539 for (unsigned i = 0; i < 256; ++i) {
540 name.push_back(i);
541 }
542 ghobject_t oid(hobject_t(sobject_t(name, CEPH_NOSNAP)));
543 int r;
544 auto ch = store->create_new_collection(cid);
545 {
546 cerr << "create collection + object" << std::endl;
547 ObjectStore::Transaction t;
548 t.create_collection(cid, 0);
549 t.touch(cid, oid);
550 r = queue_transaction(store, ch, std::move(t));
551 ASSERT_EQ(r, 0);
552 }
553 ch.reset();
554 r = store->umount();
555 ASSERT_EQ(0, r);
556 r = store->mount();
557 ASSERT_EQ(0, r);
558 {
559 cout << "removing" << std::endl;
560 ObjectStore::Transaction t;
561 t.remove(cid, oid);
562 t.remove_collection(cid);
563 auto ch = store->open_collection(cid);
564 r = queue_transaction(store, ch, std::move(t));
565 ASSERT_EQ(r, 0);
566 }
567 }
568
569 TEST_P(StoreTest, FiemapEmpty) {
570 coll_t cid;
571 int r = 0;
572 ghobject_t oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP)));
573 auto ch = store->create_new_collection(cid);
574 {
575 ObjectStore::Transaction t;
576 t.create_collection(cid, 0);
577 t.touch(cid, oid);
578 t.truncate(cid, oid, 100000);
579 r = queue_transaction(store, ch, std::move(t));
580 ASSERT_EQ(r, 0);
581 }
582 {
583 bufferlist bl;
584 store->fiemap(ch, oid, 0, 100000, bl);
585 map<uint64_t,uint64_t> m, e;
586 auto p = bl.cbegin();
587 decode(m, p);
588 cout << " got " << m << std::endl;
589 e[0] = 100000;
590 EXPECT_TRUE(m == e || m.empty());
591 }
592 {
593 ObjectStore::Transaction t;
594 t.remove(cid, oid);
595 t.remove_collection(cid);
596 cerr << "remove collection" << std::endl;
597 r = queue_transaction(store, ch, std::move(t));
598 ASSERT_EQ(r, 0);
599 }
600 }
601
602 TEST_P(StoreTest, FiemapHoles) {
603 const uint64_t MAX_EXTENTS = 4000;
604 const uint64_t SKIP_STEP = 65536;
605 coll_t cid;
606 int r = 0;
607 ghobject_t oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP)));
608 bufferlist bl;
609 bl.append("foo");
610 auto ch = store->create_new_collection(cid);
611 {
612 ObjectStore::Transaction t;
613 t.create_collection(cid, 0);
614 t.touch(cid, oid);
615 for (uint64_t i = 0; i < MAX_EXTENTS; i++)
616 t.write(cid, oid, SKIP_STEP * i, 3, bl);
617 r = queue_transaction(store, ch, std::move(t));
618 ASSERT_EQ(r, 0);
619 }
620 {
621 //fiemap test from 0 to SKIP_STEP * (MAX_EXTENTS - 1) + 3
622 bufferlist bl;
623 store->fiemap(ch, oid, 0, SKIP_STEP * (MAX_EXTENTS - 1) + 3, bl);
624 map<uint64_t,uint64_t> m, e;
625 auto p = bl.cbegin();
626 decode(m, p);
627 cout << " got " << m << std::endl;
628 ASSERT_TRUE(!m.empty());
629 ASSERT_GE(m[0], 3u);
630 auto last = m.crbegin();
631 if (m.size() == 1) {
632 ASSERT_EQ(0u, last->first);
633 } else if (m.size() == MAX_EXTENTS) {
634 for (uint64_t i = 0; i < MAX_EXTENTS; i++) {
635 ASSERT_TRUE(m.count(SKIP_STEP * i));
636 }
637 }
638 ASSERT_GT(last->first + last->second, SKIP_STEP * (MAX_EXTENTS - 1));
639 }
640 {
641 // fiemap test from SKIP_STEP to SKIP_STEP * (MAX_EXTENTS - 2) + 3
642 bufferlist bl;
643 store->fiemap(ch, oid, SKIP_STEP, SKIP_STEP * (MAX_EXTENTS - 2) + 3, bl);
644 map<uint64_t,uint64_t> m, e;
645 auto p = bl.cbegin();
646 decode(m, p);
647 cout << " got " << m << std::endl;
648 ASSERT_TRUE(!m.empty());
649 // kstore always returns [0, object_size] regardless of offset and length
650 // FIXME: if fiemap logic in kstore is refined
651 if (string(GetParam()) != "kstore") {
652 ASSERT_GE(m[SKIP_STEP], 3u);
653 auto last = m.crbegin();
654 if (m.size() == 1) {
655 ASSERT_EQ(SKIP_STEP, last->first);
656 } else if (m.size() == MAX_EXTENTS - 2) {
657 for (uint64_t i = 1; i < MAX_EXTENTS - 1; i++) {
658 ASSERT_TRUE(m.count(SKIP_STEP*i));
659 }
660 }
661 ASSERT_GT(last->first + last->second, SKIP_STEP * (MAX_EXTENTS - 1));
662 }
663 }
664 {
665 ObjectStore::Transaction t;
666 t.remove(cid, oid);
667 t.remove_collection(cid);
668 cerr << "remove collection" << std::endl;
669 r = queue_transaction(store, ch, std::move(t));
670 ASSERT_EQ(r, 0);
671 }
672 }
673
674 TEST_P(StoreTest, SimpleMetaColTest) {
675 coll_t cid;
676 int r = 0;
677 {
678 auto ch = store->create_new_collection(cid);
679 ObjectStore::Transaction t;
680 t.create_collection(cid, 0);
681 cerr << "create collection" << std::endl;
682 r = queue_transaction(store, ch, std::move(t));
683 ASSERT_EQ(r, 0);
684 }
685 {
686 ObjectStore::Transaction t;
687 t.remove_collection(cid);
688 cerr << "remove collection" << std::endl;
689 auto ch = store->open_collection(cid);
690 r = queue_transaction(store, ch, std::move(t));
691 ASSERT_EQ(r, 0);
692 }
693 {
694 auto ch = store->create_new_collection(cid);
695 ObjectStore::Transaction t;
696 t.create_collection(cid, 0);
697 cerr << "add collection" << std::endl;
698 r = queue_transaction(store, ch, std::move(t));
699 ASSERT_EQ(r, 0);
700 }
701 {
702 ObjectStore::Transaction t;
703 t.remove_collection(cid);
704 cerr << "remove collection" << std::endl;
705 auto ch = store->open_collection(cid);
706 r = queue_transaction(store, ch, std::move(t));
707 ASSERT_EQ(r, 0);
708 }
709 }
710
711 TEST_P(StoreTest, SimplePGColTest) {
712 coll_t cid(spg_t(pg_t(1,2), shard_id_t::NO_SHARD));
713 int r = 0;
714 {
715 ObjectStore::Transaction t;
716 auto ch = store->create_new_collection(cid);
717 t.create_collection(cid, 4);
718 cerr << "create collection" << std::endl;
719 r = queue_transaction(store, ch, std::move(t));
720 ASSERT_EQ(r, 0);
721 }
722 {
723 ObjectStore::Transaction t;
724 t.remove_collection(cid);
725 cerr << "remove collection" << std::endl;
726 auto ch = store->open_collection(cid);
727 r = queue_transaction(store, ch, std::move(t));
728 ASSERT_EQ(r, 0);
729 }
730 {
731 ObjectStore::Transaction t;
732 t.create_collection(cid, 4);
733 cerr << "add collection" << std::endl;
734 auto ch = store->create_new_collection(cid);
735 r = queue_transaction(store, ch, std::move(t));
736 ASSERT_EQ(r, 0);
737 }
738 {
739 ObjectStore::Transaction t;
740 t.remove_collection(cid);
741 cerr << "remove collection" << std::endl;
742 auto ch = store->open_collection(cid);
743 r = queue_transaction(store, ch, std::move(t));
744 ASSERT_EQ(r, 0);
745 }
746 }
747
748 TEST_P(StoreTest, SimpleColPreHashTest) {
749 // Firstly we will need to revert the value making sure
750 // collection hint actually works
751 int merge_threshold = g_ceph_context->_conf->filestore_merge_threshold;
752 std::ostringstream oss;
753 if (merge_threshold > 0) {
754 oss << "-" << merge_threshold;
755 SetVal(g_conf(), "filestore_merge_threshold", oss.str().c_str());
756 }
757
758 uint32_t pg_num = 128;
759
760 boost::uniform_int<> pg_id_range(0, pg_num);
761 gen_type rng(time(NULL));
762 int pg_id = pg_id_range(rng);
763
764 int objs_per_folder = abs(merge_threshold) * 16 * g_ceph_context->_conf->filestore_split_multiple;
765 boost::uniform_int<> folders_range(5, 256);
766 uint64_t expected_num_objs = (uint64_t)objs_per_folder * (uint64_t)folders_range(rng);
767
768 coll_t cid(spg_t(pg_t(pg_id, 15), shard_id_t::NO_SHARD));
769 int r;
770 auto ch = store->create_new_collection(cid);
771 {
772 // Create a collection along with a hint
773 ObjectStore::Transaction t;
774 t.create_collection(cid, 5);
775 cerr << "create collection" << std::endl;
776 bufferlist hint;
777 encode(pg_num, hint);
778 encode(expected_num_objs, hint);
779 t.collection_hint(cid, ObjectStore::Transaction::COLL_HINT_EXPECTED_NUM_OBJECTS, hint);
780 cerr << "collection hint" << std::endl;
781 r = queue_transaction(store, ch, std::move(t));
782 ASSERT_EQ(r, 0);
783 }
784 {
785 // Remove the collection
786 ObjectStore::Transaction t;
787 t.remove_collection(cid);
788 cerr << "remove collection" << std::endl;
789 r = queue_transaction(store, ch, std::move(t));
790 ASSERT_EQ(r, 0);
791 }
792 }
793
794 TEST_P(StoreTest, SmallBlockWrites) {
795 int r;
796 coll_t cid;
797 auto ch = store->create_new_collection(cid);
798 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
799 {
800 ObjectStore::Transaction t;
801 t.create_collection(cid, 0);
802 cerr << "Creating collection " << cid << std::endl;
803 r = queue_transaction(store, ch, std::move(t));
804 ASSERT_EQ(r, 0);
805 }
806 bufferlist a;
807 bufferptr ap(0x1000);
808 memset(ap.c_str(), 'a', 0x1000);
809 a.append(ap);
810 bufferlist b;
811 bufferptr bp(0x1000);
812 memset(bp.c_str(), 'b', 0x1000);
813 b.append(bp);
814 bufferlist c;
815 bufferptr cp(0x1000);
816 memset(cp.c_str(), 'c', 0x1000);
817 c.append(cp);
818 bufferptr zp(0x1000);
819 zp.zero();
820 bufferlist z;
821 z.append(zp);
822 {
823 ObjectStore::Transaction t;
824 t.write(cid, hoid, 0, 0x1000, a);
825 r = queue_transaction(store, ch, std::move(t));
826 ASSERT_EQ(r, 0);
827
828 bufferlist in, exp;
829 r = store->read(ch, hoid, 0, 0x4000, in);
830 ASSERT_EQ(0x1000, r);
831 exp.append(a);
832 ASSERT_TRUE(bl_eq(exp, in));
833 }
834 {
835 ObjectStore::Transaction t;
836 t.write(cid, hoid, 0x1000, 0x1000, b);
837 r = queue_transaction(store, ch, std::move(t));
838 ASSERT_EQ(r, 0);
839
840 bufferlist in, exp;
841 r = store->read(ch, hoid, 0, 0x4000, in);
842 ASSERT_EQ(0x2000, r);
843 exp.append(a);
844 exp.append(b);
845 ASSERT_TRUE(bl_eq(exp, in));
846 }
847 {
848 ObjectStore::Transaction t;
849 t.write(cid, hoid, 0x3000, 0x1000, c);
850 r = queue_transaction(store, ch, std::move(t));
851 ASSERT_EQ(r, 0);
852
853 bufferlist in, exp;
854 r = store->read(ch, hoid, 0, 0x4000, in);
855 ASSERT_EQ(0x4000, r);
856 exp.append(a);
857 exp.append(b);
858 exp.append(z);
859 exp.append(c);
860 ASSERT_TRUE(bl_eq(exp, in));
861 }
862 {
863 ObjectStore::Transaction t;
864 t.write(cid, hoid, 0x2000, 0x1000, a);
865 r = queue_transaction(store, ch, std::move(t));
866 ASSERT_EQ(r, 0);
867
868 bufferlist in, exp;
869 r = store->read(ch, hoid, 0, 0x4000, in);
870 ASSERT_EQ(0x4000, r);
871 exp.append(a);
872 exp.append(b);
873 exp.append(a);
874 exp.append(c);
875 ASSERT_TRUE(bl_eq(exp, in));
876 }
877 {
878 ObjectStore::Transaction t;
879 t.write(cid, hoid, 0, 0x1000, c);
880 r = queue_transaction(store, ch, std::move(t));
881 ASSERT_EQ(r, 0);
882 }
883 {
884 bufferlist in, exp;
885 r = store->read(ch, hoid, 0, 0x4000, in);
886 ASSERT_EQ(0x4000, r);
887 exp.append(c);
888 exp.append(b);
889 exp.append(a);
890 exp.append(c);
891 ASSERT_TRUE(bl_eq(exp, in));
892 }
893 {
894 ObjectStore::Transaction t;
895 t.remove(cid, hoid);
896 t.remove_collection(cid);
897 cerr << "Cleaning" << std::endl;
898 r = queue_transaction(store, ch, std::move(t));
899 ASSERT_EQ(r, 0);
900 }
901 }
902
903 TEST_P(StoreTest, BufferCacheReadTest) {
904 int r;
905 coll_t cid;
906 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
907 {
908 auto ch = store->open_collection(cid);
909 ASSERT_FALSE(ch);
910 }
911 auto ch = store->create_new_collection(cid);
912 {
913 ObjectStore::Transaction t;
914 t.create_collection(cid, 0);
915 cerr << "Creating collection " << cid << std::endl;
916 r = queue_transaction(store, ch, std::move(t));
917 ASSERT_EQ(r, 0);
918 }
919 {
920 bool exists = store->exists(ch, hoid);
921 ASSERT_TRUE(!exists);
922
923 ObjectStore::Transaction t;
924 t.touch(cid, hoid);
925 cerr << "Creating object " << hoid << std::endl;
926 r = queue_transaction(store, ch, std::move(t));
927 ASSERT_EQ(r, 0);
928
929 exists = store->exists(ch, hoid);
930 ASSERT_EQ(true, exists);
931 }
932 {
933 ObjectStore::Transaction t;
934 bufferlist bl, newdata;
935 bl.append("abcde");
936 t.write(cid, hoid, 0, 5, bl);
937 t.write(cid, hoid, 10, 5, bl);
938 cerr << "TwinWrite" << std::endl;
939 r = queue_transaction(store, ch, std::move(t));
940 ASSERT_EQ(r, 0);
941
942 r = store->read(ch, hoid, 0, 15, newdata);
943 ASSERT_EQ(r, 15);
944 {
945 bufferlist expected;
946 expected.append(bl);
947 expected.append_zero(5);
948 expected.append(bl);
949 ASSERT_TRUE(bl_eq(expected, newdata));
950 }
951 }
952 //overwrite over the same extents
953 {
954 ObjectStore::Transaction t;
955 bufferlist bl, newdata;
956 bl.append("edcba");
957 t.write(cid, hoid, 0, 5, bl);
958 t.write(cid, hoid, 10, 5, bl);
959 cerr << "TwinWrite" << std::endl;
960 r = queue_transaction(store, ch, std::move(t));
961 ASSERT_EQ(r, 0);
962
963 r = store->read(ch, hoid, 0, 15, newdata);
964 ASSERT_EQ(r, 15);
965 {
966 bufferlist expected;
967 expected.append(bl);
968 expected.append_zero(5);
969 expected.append(bl);
970 ASSERT_TRUE(bl_eq(expected, newdata));
971 }
972 }
973 //additional write to an unused region of some blob
974 {
975 ObjectStore::Transaction t;
976 bufferlist bl2, newdata;
977 bl2.append("1234567890");
978
979 t.write(cid, hoid, 20, bl2.length(), bl2);
980 cerr << "Append" << std::endl;
981 r = queue_transaction(store, ch, std::move(t));
982 ASSERT_EQ(r, 0);
983
984 r = store->read(ch, hoid, 0, 30, newdata);
985 ASSERT_EQ(r, 30);
986 {
987 bufferlist expected;
988 expected.append("edcba");
989 expected.append_zero(5);
990 expected.append("edcba");
991 expected.append_zero(5);
992 expected.append(bl2);
993
994 ASSERT_TRUE(bl_eq(expected, newdata));
995 }
996 }
997 //additional write to an unused region of some blob and partial owerite over existing extents
998 {
999 ObjectStore::Transaction t;
1000 bufferlist bl, bl2, bl3, newdata;
1001 bl.append("DCB");
1002 bl2.append("1234567890");
1003 bl3.append("BA");
1004
1005 t.write(cid, hoid, 30, bl2.length(), bl2);
1006 t.write(cid, hoid, 1, bl.length(), bl);
1007 t.write(cid, hoid, 13, bl3.length(), bl3);
1008 cerr << "TripleWrite" << std::endl;
1009 r = queue_transaction(store, ch, std::move(t));
1010 ASSERT_EQ(r, 0);
1011
1012 r = store->read(ch, hoid, 0, 40, newdata);
1013 ASSERT_EQ(r, 40);
1014 {
1015 bufferlist expected;
1016 expected.append("eDCBa");
1017 expected.append_zero(5);
1018 expected.append("edcBA");
1019 expected.append_zero(5);
1020 expected.append(bl2);
1021 expected.append(bl2);
1022
1023 ASSERT_TRUE(bl_eq(expected, newdata));
1024 }
1025 }
1026 }
1027
1028 void StoreTest::doCompressionTest()
1029 {
1030 int r;
1031 coll_t cid;
1032 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1033 {
1034 auto ch = store->open_collection(cid);
1035 ASSERT_FALSE(ch);
1036 }
1037 auto ch = store->create_new_collection(cid);
1038 {
1039 ObjectStore::Transaction t;
1040 t.create_collection(cid, 0);
1041 cerr << "Creating collection " << cid << std::endl;
1042 r = queue_transaction(store, ch, std::move(t));
1043 ASSERT_EQ(r, 0);
1044 }
1045 {
1046 bool exists = store->exists(ch, hoid);
1047 ASSERT_TRUE(!exists);
1048
1049 ObjectStore::Transaction t;
1050 t.touch(cid, hoid);
1051 cerr << "Creating object " << hoid << std::endl;
1052 r = queue_transaction(store, ch, std::move(t));
1053 ASSERT_EQ(r, 0);
1054
1055 exists = store->exists(ch, hoid);
1056 ASSERT_EQ(true, exists);
1057 }
1058 std::string data;
1059 data.resize(0x10000 * 4);
1060 for(size_t i = 0;i < data.size(); i++)
1061 data[i] = i / 256;
1062 {
1063 ObjectStore::Transaction t;
1064 bufferlist bl, newdata;
1065 bl.append(data);
1066 t.write(cid, hoid, 0, bl.length(), bl);
1067 cerr << "CompressibleData (4xAU) Write" << std::endl;
1068 r = queue_transaction(store, ch, std::move(t));
1069 ASSERT_EQ(r, 0);
1070
1071 r = store->read(ch, hoid, 0, data.size() , newdata);
1072
1073 ASSERT_EQ(r, (int)data.size());
1074 {
1075 bufferlist expected;
1076 expected.append(data);
1077 ASSERT_TRUE(bl_eq(expected, newdata));
1078 }
1079 newdata.clear();
1080 r = store->read(ch, hoid, 0, 711 , newdata);
1081 ASSERT_EQ(r, 711);
1082 {
1083 bufferlist expected;
1084 expected.append(data.substr(0,711));
1085 ASSERT_TRUE(bl_eq(expected, newdata));
1086 }
1087 newdata.clear();
1088 r = store->read(ch, hoid, 0xf00f, data.size(), newdata);
1089 ASSERT_EQ(r, int(data.size() - 0xf00f) );
1090 {
1091 bufferlist expected;
1092 expected.append(data.substr(0xf00f));
1093 ASSERT_TRUE(bl_eq(expected, newdata));
1094 }
1095 {
1096 struct store_statfs_t statfs;
1097 int r = store->statfs(&statfs);
1098 ASSERT_EQ(r, 0);
1099 ASSERT_EQ(statfs.data_stored, (unsigned)data.size());
1100 ASSERT_LE(statfs.data_compressed, (unsigned)data.size());
1101 ASSERT_EQ(statfs.data_compressed_original, (unsigned)data.size());
1102 ASSERT_LE(statfs.data_compressed_allocated, (unsigned)data.size());
1103 }
1104 }
1105 std::string data2;
1106 data2.resize(0x10000 * 4 - 0x9000);
1107 for(size_t i = 0;i < data2.size(); i++)
1108 data2[i] = (i+1) / 256;
1109 {
1110 ObjectStore::Transaction t;
1111 bufferlist bl, newdata;
1112 bl.append(data2);
1113 t.write(cid, hoid, 0x8000, bl.length(), bl);
1114 cerr << "CompressibleData partial overwrite" << std::endl;
1115 r = queue_transaction(store, ch, std::move(t));
1116 ASSERT_EQ(r, 0);
1117
1118 r = store->read(ch, hoid, 0, 0x10000, newdata);
1119 ASSERT_EQ(r, (int)0x10000);
1120 {
1121 bufferlist expected;
1122 expected.append(data.substr(0, 0x8000));
1123 expected.append(data2.substr(0, 0x8000));
1124 ASSERT_TRUE(bl_eq(expected, newdata));
1125 }
1126 newdata.clear();
1127 r = store->read(ch, hoid, 0x9000, 711 , newdata);
1128 ASSERT_EQ(r, 711);
1129 {
1130 bufferlist expected;
1131 expected.append(data2.substr(0x1000,711));
1132 ASSERT_TRUE(bl_eq(expected, newdata));
1133 }
1134 newdata.clear();
1135 r = store->read(ch, hoid, 0x0, 0x40000, newdata);
1136 ASSERT_EQ(r, int(0x40000) );
1137 {
1138 bufferlist expected;
1139 expected.append(data.substr(0, 0x8000));
1140 expected.append(data2.substr(0, 0x37000));
1141 expected.append(data.substr(0x3f000, 0x1000));
1142 ASSERT_TRUE(bl_eq(expected, newdata));
1143 }
1144 }
1145 data2.resize(0x3f000);
1146 for(size_t i = 0;i < data2.size(); i++)
1147 data2[i] = (i+2) / 256;
1148 {
1149 ObjectStore::Transaction t;
1150 bufferlist bl, newdata;
1151 bl.append(data2);
1152 t.write(cid, hoid, 0, bl.length(), bl);
1153 cerr << "CompressibleData partial overwrite, two extents overlapped, single one to be removed" << std::endl;
1154 r = queue_transaction(store, ch, std::move(t));
1155 ASSERT_EQ(r, 0);
1156
1157 r = store->read(ch, hoid, 0, 0x3e000 - 1, newdata);
1158 ASSERT_EQ(r, (int)0x3e000 - 1);
1159 {
1160 bufferlist expected;
1161 expected.append(data2.substr(0, 0x3e000 - 1));
1162 ASSERT_TRUE(bl_eq(expected, newdata));
1163 }
1164 newdata.clear();
1165 r = store->read(ch, hoid, 0x3e000-1, 0x2001, newdata);
1166 ASSERT_EQ(r, 0x2001);
1167 {
1168 bufferlist expected;
1169 expected.append(data2.substr(0x3e000-1, 0x1001));
1170 expected.append(data.substr(0x3f000, 0x1000));
1171 ASSERT_TRUE(bl_eq(expected, newdata));
1172 }
1173 newdata.clear();
1174 r = store->read(ch, hoid, 0x0, 0x40000, newdata);
1175 ASSERT_EQ(r, int(0x40000) );
1176 {
1177 bufferlist expected;
1178 expected.append(data2.substr(0, 0x3f000));
1179 expected.append(data.substr(0x3f000, 0x1000));
1180 ASSERT_TRUE(bl_eq(expected, newdata));
1181 }
1182 }
1183 data.resize(0x1001);
1184 for(size_t i = 0;i < data.size(); i++)
1185 data[i] = (i+3) / 256;
1186 {
1187 ObjectStore::Transaction t;
1188 bufferlist bl, newdata;
1189 bl.append(data);
1190 t.write(cid, hoid, 0x3f000-1, bl.length(), bl);
1191 cerr << "Small chunk partial overwrite, two extents overlapped, single one to be removed" << std::endl;
1192 r = queue_transaction(store, ch, std::move(t));
1193 ASSERT_EQ(r, 0);
1194
1195 r = store->read(ch, hoid, 0x3e000, 0x2000, newdata);
1196 ASSERT_EQ(r, (int)0x2000);
1197 {
1198 bufferlist expected;
1199 expected.append(data2.substr(0x3e000, 0x1000 - 1));
1200 expected.append(data.substr(0, 0x1001));
1201 ASSERT_TRUE(bl_eq(expected, newdata));
1202 }
1203 }
1204 {
1205 ObjectStore::Transaction t;
1206 t.remove(cid, hoid);
1207 cerr << "Cleaning object" << std::endl;
1208 r = queue_transaction(store, ch, std::move(t));
1209 ASSERT_EQ(r, 0);
1210 }
1211 //force fsck
1212 ch.reset();
1213 EXPECT_EQ(store->umount(), 0);
1214 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1215 EXPECT_EQ(store->mount(), 0);
1216 ch = store->open_collection(cid);
1217 auto settingsBookmark = BookmarkSettings();
1218 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
1219 g_ceph_context->_conf.apply_changes(nullptr);
1220 {
1221 data.resize(0x10000*6);
1222
1223 for(size_t i = 0;i < data.size(); i++)
1224 data[i] = i / 256;
1225 ObjectStore::Transaction t;
1226 bufferlist bl, newdata;
1227 bl.append(data);
1228 t.write(cid, hoid, 0, bl.length(), bl);
1229 cerr << "CompressibleData large blob" << std::endl;
1230 r = queue_transaction(store, ch, std::move(t));
1231 ASSERT_EQ(r, 0);
1232 }
1233 //force fsck
1234 ch.reset();
1235 EXPECT_EQ(store->umount(), 0);
1236 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1237 EXPECT_EQ(store->mount(), 0);
1238 ch = store->open_collection(cid);
1239 {
1240 ObjectStore::Transaction t;
1241 t.remove(cid, hoid);
1242 t.remove_collection(cid);
1243 cerr << "Cleaning" << std::endl;
1244 r = queue_transaction(store, ch, std::move(t));
1245 ASSERT_EQ(r, 0);
1246 }
1247 }
1248
1249 TEST_P(StoreTest, CompressionTest) {
1250 if (string(GetParam()) != "bluestore")
1251 return;
1252 if (smr) {
1253 cout << "TODO: need to adjust statfs check for smr" << std::endl;
1254 return;
1255 }
1256
1257 SetVal(g_conf(), "bluestore_compression_algorithm", "snappy");
1258 SetVal(g_conf(), "bluestore_compression_mode", "force");
1259 g_ceph_context->_conf.apply_changes(nullptr);
1260 doCompressionTest();
1261
1262 SetVal(g_conf(), "bluestore_compression_algorithm", "zlib");
1263 SetVal(g_conf(), "bluestore_compression_mode", "aggressive");
1264 g_ceph_context->_conf.apply_changes(nullptr);
1265 doCompressionTest();
1266 }
1267
1268 TEST_P(StoreTest, SimpleObjectTest) {
1269 int r;
1270 coll_t cid;
1271 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1272 {
1273 auto ch = store->open_collection(cid);
1274 ASSERT_FALSE(ch);
1275 }
1276 auto ch = store->create_new_collection(cid);
1277 {
1278 ObjectStore::Transaction t;
1279 t.create_collection(cid, 0);
1280 cerr << "Creating collection " << cid << std::endl;
1281 r = queue_transaction(store, ch, std::move(t));
1282 ASSERT_EQ(r, 0);
1283 }
1284 {
1285 bool exists = store->exists(ch, hoid);
1286 ASSERT_TRUE(!exists);
1287
1288 ObjectStore::Transaction t;
1289 t.touch(cid, hoid);
1290 cerr << "Creating object " << hoid << std::endl;
1291 r = queue_transaction(store, ch, std::move(t));
1292 ASSERT_EQ(r, 0);
1293
1294 exists = store->exists(ch, hoid);
1295 ASSERT_EQ(true, exists);
1296 }
1297 {
1298 ObjectStore::Transaction t;
1299 t.remove(cid, hoid);
1300 t.touch(cid, hoid);
1301 cerr << "Remove then create" << std::endl;
1302 r = queue_transaction(store, ch, std::move(t));
1303 ASSERT_EQ(r, 0);
1304 }
1305 {
1306 ObjectStore::Transaction t;
1307 bufferlist bl, orig;
1308 bl.append("abcde");
1309 orig = bl;
1310 t.remove(cid, hoid);
1311 t.write(cid, hoid, 0, 5, bl);
1312 cerr << "Remove then create" << std::endl;
1313 r = queue_transaction(store, ch, std::move(t));
1314 ASSERT_EQ(r, 0);
1315
1316 bufferlist in;
1317 r = store->read(ch, hoid, 0, 5, in);
1318 ASSERT_EQ(5, r);
1319 ASSERT_TRUE(bl_eq(orig, in));
1320 }
1321 {
1322 ObjectStore::Transaction t;
1323 bufferlist bl, exp;
1324 bl.append("abcde");
1325 exp = bl;
1326 exp.append(bl);
1327 t.write(cid, hoid, 5, 5, bl);
1328 cerr << "Append" << std::endl;
1329 r = queue_transaction(store, ch, std::move(t));
1330 ASSERT_EQ(r, 0);
1331
1332 bufferlist in;
1333 r = store->read(ch, hoid, 0, 10, in);
1334 ASSERT_EQ(10, r);
1335 ASSERT_TRUE(bl_eq(exp, in));
1336 }
1337 {
1338 ObjectStore::Transaction t;
1339 bufferlist bl, exp;
1340 bl.append("abcdeabcde");
1341 exp = bl;
1342 t.write(cid, hoid, 0, 10, bl);
1343 cerr << "Full overwrite" << std::endl;
1344 r = queue_transaction(store, ch, std::move(t));
1345 ASSERT_EQ(r, 0);
1346
1347 bufferlist in;
1348 r = store->read(ch, hoid, 0, 10, in);
1349 ASSERT_EQ(10, r);
1350 ASSERT_TRUE(bl_eq(exp, in));
1351 }
1352 {
1353 ObjectStore::Transaction t;
1354 bufferlist bl;
1355 bl.append("abcde");
1356 t.write(cid, hoid, 3, 5, bl);
1357 cerr << "Partial overwrite" << std::endl;
1358 r = queue_transaction(store, ch, std::move(t));
1359 ASSERT_EQ(r, 0);
1360
1361 bufferlist in, exp;
1362 exp.append("abcabcdede");
1363 r = store->read(ch, hoid, 0, 10, in);
1364 ASSERT_EQ(10, r);
1365 in.hexdump(cout);
1366 ASSERT_TRUE(bl_eq(exp, in));
1367 }
1368 {
1369 {
1370 ObjectStore::Transaction t;
1371 bufferlist bl;
1372 bl.append("fghij");
1373 t.truncate(cid, hoid, 0);
1374 t.write(cid, hoid, 5, 5, bl);
1375 cerr << "Truncate + hole" << std::endl;
1376 r = queue_transaction(store, ch, std::move(t));
1377 ASSERT_EQ(r, 0);
1378 }
1379 {
1380 ObjectStore::Transaction t;
1381 bufferlist bl;
1382 bl.append("abcde");
1383 t.write(cid, hoid, 0, 5, bl);
1384 cerr << "Reverse fill-in" << std::endl;
1385 r = queue_transaction(store, ch, std::move(t));
1386 ASSERT_EQ(r, 0);
1387 }
1388
1389 bufferlist in, exp;
1390 exp.append("abcdefghij");
1391 r = store->read(ch, hoid, 0, 10, in);
1392 ASSERT_EQ(10, r);
1393 in.hexdump(cout);
1394 ASSERT_TRUE(bl_eq(exp, in));
1395 }
1396 {
1397 ObjectStore::Transaction t;
1398 bufferlist bl;
1399 bl.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1400 t.write(cid, hoid, 0, bl.length(), bl);
1401 cerr << "larger overwrite" << std::endl;
1402 r = queue_transaction(store, ch, std::move(t));
1403 ASSERT_EQ(r, 0);
1404
1405 bufferlist in;
1406 r = store->read(ch, hoid, 0, bl.length(), in);
1407 ASSERT_EQ((int)bl.length(), r);
1408 in.hexdump(cout);
1409 ASSERT_TRUE(bl_eq(bl, in));
1410 }
1411 {
1412 bufferlist bl;
1413 bl.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1414
1415 //test: offset=len=0 mean read all data
1416 bufferlist in;
1417 r = store->read(ch, hoid, 0, 0, in);
1418 ASSERT_EQ((int)bl.length(), r);
1419 in.hexdump(cout);
1420 ASSERT_TRUE(bl_eq(bl, in));
1421 }
1422 {
1423 //verifying unaligned csums
1424 std::string s1("1"), s2(0x1000, '2'), s3("00");
1425 {
1426 ObjectStore::Transaction t;
1427 bufferlist bl;
1428 bl.append(s1);
1429 bl.append(s2);
1430 t.truncate(cid, hoid, 0);
1431 t.write(cid, hoid, 0x1000-1, bl.length(), bl);
1432 cerr << "Write unaligned csum, stage 1" << std::endl;
1433 r = queue_transaction(store, ch, std::move(t));
1434 ASSERT_EQ(r, 0);
1435 }
1436
1437 bufferlist in, exp1, exp2, exp3;
1438 exp1.append(s1);
1439 exp2.append(s2);
1440 exp3.append(s3);
1441 r = store->read(ch, hoid, 0x1000-1, 1, in);
1442 ASSERT_EQ(1, r);
1443 ASSERT_TRUE(bl_eq(exp1, in));
1444 in.clear();
1445 r = store->read(ch, hoid, 0x1000, 0x1000, in);
1446 ASSERT_EQ(0x1000, r);
1447 ASSERT_TRUE(bl_eq(exp2, in));
1448
1449 {
1450 ObjectStore::Transaction t;
1451 bufferlist bl;
1452 bl.append(s3);
1453 t.write(cid, hoid, 1, bl.length(), bl);
1454 cerr << "Write unaligned csum, stage 2" << std::endl;
1455 r = queue_transaction(store, ch, std::move(t));
1456 ASSERT_EQ(r, 0);
1457 }
1458 in.clear();
1459 r = store->read(ch, hoid, 1, 2, in);
1460 ASSERT_EQ(2, r);
1461 ASSERT_TRUE(bl_eq(exp3, in));
1462 in.clear();
1463 r = store->read(ch, hoid, 0x1000-1, 1, in);
1464 ASSERT_EQ(1, r);
1465 ASSERT_TRUE(bl_eq(exp1, in));
1466 in.clear();
1467 r = store->read(ch, hoid, 0x1000, 0x1000, in);
1468 ASSERT_EQ(0x1000, r);
1469 ASSERT_TRUE(bl_eq(exp2, in));
1470
1471 }
1472
1473 {
1474 ObjectStore::Transaction t;
1475 t.remove(cid, hoid);
1476 t.remove_collection(cid);
1477 cerr << "Cleaning" << std::endl;
1478 r = queue_transaction(store, ch, std::move(t));
1479 ASSERT_EQ(r, 0);
1480 }
1481 }
1482
1483 #if defined(WITH_BLUESTORE)
1484
1485 TEST_P(StoreTestSpecificAUSize, ReproBug41901Test) {
1486 if(string(GetParam()) != "bluestore")
1487 return;
1488 if (smr) {
1489 cout << "SKIP (smr)" << std::endl;
1490 return;
1491 }
1492
1493 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1494 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
1495 g_conf().apply_changes(nullptr);
1496 StartDeferred(65536);
1497
1498 int r;
1499 coll_t cid;
1500 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1501 const PerfCounters* logger = store->get_perf_counters();
1502 auto ch = store->create_new_collection(cid);
1503 {
1504 ObjectStore::Transaction t;
1505 t.create_collection(cid, 0);
1506 cerr << "Creating collection " << cid << std::endl;
1507 r = queue_transaction(store, ch, std::move(t));
1508 ASSERT_EQ(r, 0);
1509 }
1510 {
1511 bool exists = store->exists(ch, hoid);
1512 ASSERT_TRUE(!exists);
1513
1514 ObjectStore::Transaction t;
1515 t.touch(cid, hoid);
1516 cerr << "Creating object " << hoid << std::endl;
1517 r = queue_transaction(store, ch, std::move(t));
1518 ASSERT_EQ(r, 0);
1519
1520 exists = store->exists(ch, hoid);
1521 ASSERT_EQ(true, exists);
1522 }
1523 {
1524 ObjectStore::Transaction t;
1525 bufferlist bl, orig;
1526 string s(4096, 'a');
1527 bl.append(s);
1528 t.write(cid, hoid, 0x11000, bl.length(), bl);
1529 cerr << "write1" << std::endl;
1530 r = queue_transaction(store, ch, std::move(t));
1531 ASSERT_EQ(r, 0);
1532 }
1533 {
1534 ObjectStore::Transaction t;
1535 bufferlist bl, orig;
1536 string s(4096 * 3, 'a');
1537 bl.append(s);
1538 t.write(cid, hoid, 0x15000, bl.length(), bl);
1539 cerr << "write2" << std::endl;
1540 r = queue_transaction(store, ch, std::move(t));
1541 ASSERT_EQ(r, 0);
1542 }
1543 ASSERT_EQ(logger->get(l_bluestore_write_small), 2u);
1544 ASSERT_EQ(logger->get(l_bluestore_write_small_unused), 1u);
1545
1546 {
1547 ObjectStore::Transaction t;
1548 bufferlist bl, orig;
1549 string s(4096 * 2, 'a');
1550 bl.append(s);
1551 t.write(cid, hoid, 0xe000, bl.length(), bl);
1552 cerr << "write3" << std::endl;
1553 r = queue_transaction(store, ch, std::move(t));
1554 ASSERT_EQ(r, 0);
1555 }
1556 ASSERT_EQ(logger->get(l_bluestore_write_small), 3u);
1557 ASSERT_EQ(logger->get(l_bluestore_write_small_unused), 2u);
1558
1559
1560 {
1561 ObjectStore::Transaction t;
1562 bufferlist bl, orig;
1563 string s(4096, 'a');
1564 bl.append(s);
1565 t.write(cid, hoid, 0xf000, bl.length(), bl);
1566 t.write(cid, hoid, 0x10000, bl.length(), bl);
1567 cerr << "write3" << std::endl;
1568 r = queue_transaction(store, ch, std::move(t));
1569 ASSERT_EQ(r, 0);
1570 }
1571 ASSERT_EQ(logger->get(l_bluestore_write_small), 5u);
1572 ASSERT_EQ(logger->get(l_bluestore_write_small_unused), 2u);
1573 {
1574 ObjectStore::Transaction t;
1575 t.remove(cid, hoid);
1576 t.remove_collection(cid);
1577 cerr << "Cleaning" << std::endl;
1578 r = queue_transaction(store, ch, std::move(t));
1579 ASSERT_EQ(r, 0);
1580 }
1581 }
1582
1583
1584 TEST_P(StoreTestSpecificAUSize, BluestoreStatFSTest) {
1585 if(string(GetParam()) != "bluestore")
1586 return;
1587 if (smr) {
1588 cout << "TODO: fix this for smr" << std::endl;
1589 return;
1590 }
1591 SetVal(g_conf(), "bluestore_block_db_path", "");
1592 StartDeferred(65536);
1593 SetVal(g_conf(), "bluestore_compression_mode", "force");
1594 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
1595 // just a big number to disble gc
1596 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "100000");
1597 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
1598 g_conf().apply_changes(nullptr);
1599 int r;
1600
1601 int poolid = 4373;
1602 coll_t cid = coll_t(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
1603 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
1604 string(),
1605 0,
1606 poolid,
1607 string()));
1608 ghobject_t hoid2 = hoid;
1609 hoid2.hobj.snap = 1;
1610 {
1611 auto ch = store->open_collection(cid);
1612 ASSERT_FALSE(ch);
1613 }
1614 auto ch = store->create_new_collection(cid);
1615 {
1616 ObjectStore::Transaction t;
1617 t.create_collection(cid, 0);
1618 cerr << "Creating collection " << cid << std::endl;
1619 r = queue_transaction(store, ch, std::move(t));
1620 ASSERT_EQ(r, 0);
1621 }
1622 {
1623 bool exists = store->exists(ch, hoid);
1624 ASSERT_TRUE(!exists);
1625
1626 ObjectStore::Transaction t;
1627 t.touch(cid, hoid);
1628 cerr << "Creating object " << hoid << std::endl;
1629 r = queue_transaction(store, ch, std::move(t));
1630 ASSERT_EQ(r, 0);
1631
1632 exists = store->exists(ch, hoid);
1633 ASSERT_EQ(true, exists);
1634 }
1635 {
1636 struct store_statfs_t statfs;
1637 int r = store->statfs(&statfs);
1638 ASSERT_EQ(r, 0);
1639 ASSERT_EQ( 0u, statfs.allocated);
1640 ASSERT_EQ( 0u, statfs.data_stored);
1641 ASSERT_EQ(g_conf()->bluestore_block_size, statfs.total);
1642 ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf()->bluestore_block_size);
1643
1644 struct store_statfs_t statfs_pool;
1645 bool per_pool_omap;
1646 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1647 ASSERT_EQ(r, 0);
1648 ASSERT_EQ( 0u, statfs_pool.allocated);
1649 ASSERT_EQ( 0u, statfs_pool.data_stored);
1650
1651 //force fsck
1652 ch.reset();
1653 EXPECT_EQ(store->umount(), 0);
1654 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1655 EXPECT_EQ(store->mount(), 0);
1656 ch = store->open_collection(cid);
1657 }
1658 {
1659 ObjectStore::Transaction t;
1660 bufferlist bl;
1661 bl.append("abcde");
1662 t.write(cid, hoid, 0, 5, bl);
1663 cerr << "Append 5 bytes" << std::endl;
1664 r = queue_transaction(store, ch, std::move(t));
1665 ASSERT_EQ(r, 0);
1666
1667 struct store_statfs_t statfs;
1668 int r = store->statfs(&statfs);
1669 ASSERT_EQ(r, 0);
1670 ASSERT_EQ(5, statfs.data_stored);
1671 ASSERT_EQ(0x10000, statfs.allocated);
1672 ASSERT_EQ(0, statfs.data_compressed);
1673 ASSERT_EQ(0, statfs.data_compressed_original);
1674 ASSERT_EQ(0, statfs.data_compressed_allocated);
1675
1676 struct store_statfs_t statfs_pool;
1677 bool per_pool_omap;
1678 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1679 ASSERT_EQ(r, 0);
1680 ASSERT_EQ(5, statfs_pool.data_stored);
1681 ASSERT_EQ(0x10000, statfs_pool.allocated);
1682 ASSERT_EQ(0, statfs_pool.data_compressed);
1683 ASSERT_EQ(0, statfs_pool.data_compressed_original);
1684 ASSERT_EQ(0, statfs_pool.data_compressed_allocated);
1685
1686 // accessing unknown pool
1687 r = store->pool_statfs(poolid + 1, &statfs_pool, &per_pool_omap);
1688 ASSERT_EQ(r, 0);
1689 ASSERT_EQ(0, statfs_pool.data_stored);
1690 ASSERT_EQ(0, statfs_pool.allocated);
1691 ASSERT_EQ(0, statfs_pool.data_compressed);
1692 ASSERT_EQ(0, statfs_pool.data_compressed_original);
1693 ASSERT_EQ(0, statfs_pool.data_compressed_allocated);
1694
1695 //force fsck
1696 ch.reset();
1697 EXPECT_EQ(store->umount(), 0);
1698 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1699 EXPECT_EQ(store->mount(), 0);
1700 ch = store->open_collection(cid);
1701 }
1702 {
1703 ObjectStore::Transaction t;
1704 std::string s(0x30000, 'a');
1705 bufferlist bl;
1706 bl.append(s);
1707 t.write(cid, hoid, 0x10000, bl.length(), bl);
1708 cerr << "Append 0x30000 compressible bytes" << std::endl;
1709 r = queue_transaction(store, ch, std::move(t));
1710 ASSERT_EQ(r, 0);
1711
1712 struct store_statfs_t statfs;
1713 int r = store->statfs(&statfs);
1714 ASSERT_EQ(r, 0);
1715 ASSERT_EQ(0x30005, statfs.data_stored);
1716 ASSERT_EQ(0x30000, statfs.allocated);
1717 ASSERT_LE(statfs.data_compressed, 0x10000);
1718 ASSERT_EQ(0x20000, statfs.data_compressed_original);
1719 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
1720
1721 struct store_statfs_t statfs_pool;
1722 bool per_pool_omap;
1723 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1724 ASSERT_EQ(r, 0);
1725 ASSERT_EQ(0x30005, statfs_pool.data_stored);
1726 ASSERT_EQ(0x30000, statfs_pool.allocated);
1727 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1728 ASSERT_EQ(0x20000, statfs_pool.data_compressed_original);
1729 ASSERT_EQ(statfs_pool.data_compressed_allocated, 0x10000);
1730 //force fsck
1731 ch.reset();
1732 EXPECT_EQ(store->umount(), 0);
1733 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1734 EXPECT_EQ(store->mount(), 0);
1735 ch = store->open_collection(cid);
1736 }
1737 {
1738 ObjectStore::Transaction t;
1739 t.zero(cid, hoid, 1, 3);
1740 t.zero(cid, hoid, 0x20000, 9);
1741 cerr << "Punch hole at 1~3, 0x20000~9" << std::endl;
1742 r = queue_transaction(store, ch, std::move(t));
1743 ASSERT_EQ(r, 0);
1744
1745 struct store_statfs_t statfs;
1746 int r = store->statfs(&statfs);
1747 ASSERT_EQ(r, 0);
1748 ASSERT_EQ(0x30005 - 3 - 9, statfs.data_stored);
1749 ASSERT_EQ(0x30000, statfs.allocated);
1750 ASSERT_LE(statfs.data_compressed, 0x10000);
1751 ASSERT_EQ(0x20000 - 9, statfs.data_compressed_original);
1752 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
1753
1754 struct store_statfs_t statfs_pool;
1755 bool per_pool_omap;
1756 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1757 ASSERT_EQ(r, 0);
1758 ASSERT_EQ(0x30005 - 3 - 9, statfs_pool.data_stored);
1759 ASSERT_EQ(0x30000, statfs_pool.allocated);
1760 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1761 ASSERT_EQ(0x20000 - 9, statfs_pool.data_compressed_original);
1762 ASSERT_EQ(statfs_pool.data_compressed_allocated, 0x10000);
1763 //force fsck
1764 ch.reset();
1765 EXPECT_EQ(store->umount(), 0);
1766 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1767 EXPECT_EQ(store->mount(), 0);
1768 ch = store->open_collection(cid);
1769 }
1770 {
1771 ObjectStore::Transaction t;
1772 std::string s(0x1000, 'b');
1773 bufferlist bl;
1774 bl.append(s);
1775 t.write(cid, hoid, 1, bl.length(), bl);
1776 t.write(cid, hoid, 0x10001, bl.length(), bl);
1777 cerr << "Overwrite first and second(compressible) extents" << std::endl;
1778 r = queue_transaction(store, ch, std::move(t));
1779 ASSERT_EQ(r, 0);
1780
1781 struct store_statfs_t statfs;
1782 int r = store->statfs(&statfs);
1783 ASSERT_EQ(r, 0);
1784 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs.data_stored);
1785 ASSERT_EQ(0x40000, statfs.allocated);
1786 ASSERT_LE(statfs.data_compressed, 0x10000);
1787 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs.data_compressed_original);
1788 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
1789
1790 struct store_statfs_t statfs_pool;
1791 bool per_pool_omap;
1792 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1793 ASSERT_EQ(r, 0);
1794 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs_pool.data_stored);
1795 ASSERT_EQ(0x40000, statfs_pool.allocated);
1796 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1797 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs_pool.data_compressed_original);
1798 ASSERT_EQ(statfs_pool.data_compressed_allocated, 0x10000);
1799 //force fsck
1800 ch.reset();
1801 EXPECT_EQ(store->umount(), 0);
1802 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1803 EXPECT_EQ(store->mount(), 0);
1804 ch = store->open_collection(cid);
1805 }
1806 {
1807 ObjectStore::Transaction t;
1808 std::string s(0x10000, 'c');
1809 bufferlist bl;
1810 bl.append(s);
1811 t.write(cid, hoid, 0x10000, bl.length(), bl);
1812 t.write(cid, hoid, 0x20000, bl.length(), bl);
1813 t.write(cid, hoid, 0x30000, bl.length(), bl);
1814 cerr << "Overwrite compressed extent with 3 uncompressible ones" << std::endl;
1815 r = queue_transaction(store, ch, std::move(t));
1816 ASSERT_EQ(r, 0);
1817
1818 struct store_statfs_t statfs;
1819 int r = store->statfs(&statfs);
1820 ASSERT_EQ(r, 0);
1821 ASSERT_EQ(0x30000 + 0x1001, statfs.data_stored);
1822 ASSERT_EQ(0x40000, statfs.allocated);
1823 ASSERT_LE(statfs.data_compressed, 0);
1824 ASSERT_EQ(0, statfs.data_compressed_original);
1825 ASSERT_EQ(0, statfs.data_compressed_allocated);
1826
1827 struct store_statfs_t statfs_pool;
1828 bool per_pool_omap;
1829 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1830 ASSERT_EQ(r, 0);
1831 ASSERT_EQ(0x30000 + 0x1001, statfs_pool.data_stored);
1832 ASSERT_EQ(0x40000, statfs_pool.allocated);
1833 ASSERT_LE(statfs_pool.data_compressed, 0);
1834 ASSERT_EQ(0, statfs_pool.data_compressed_original);
1835 ASSERT_EQ(0, statfs_pool.data_compressed_allocated);
1836 //force fsck
1837 ch.reset();
1838 EXPECT_EQ(store->umount(), 0);
1839 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1840 EXPECT_EQ(store->mount(), 0);
1841 ch = store->open_collection(cid);
1842 }
1843 {
1844 ObjectStore::Transaction t;
1845 t.zero(cid, hoid, 0, 0x40000);
1846 cerr << "Zero object" << std::endl;
1847 r = queue_transaction(store, ch, std::move(t));
1848 ASSERT_EQ(r, 0);
1849 struct store_statfs_t statfs;
1850 int r = store->statfs(&statfs);
1851 ASSERT_EQ(r, 0);
1852 ASSERT_EQ(0u, statfs.allocated);
1853 ASSERT_EQ(0u, statfs.data_stored);
1854 ASSERT_EQ(0u, statfs.data_compressed_original);
1855 ASSERT_EQ(0u, statfs.data_compressed);
1856 ASSERT_EQ(0u, statfs.data_compressed_allocated);
1857
1858 struct store_statfs_t statfs_pool;
1859 bool per_pool_omap;
1860 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1861 ASSERT_EQ(r, 0);
1862 ASSERT_EQ(0u, statfs_pool.allocated);
1863 ASSERT_EQ(0u, statfs_pool.data_stored);
1864 ASSERT_EQ(0u, statfs_pool.data_compressed_original);
1865 ASSERT_EQ(0u, statfs_pool.data_compressed);
1866 ASSERT_EQ(0u, statfs_pool.data_compressed_allocated);
1867 //force fsck
1868 ch.reset();
1869 EXPECT_EQ(store->umount(), 0);
1870 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1871 EXPECT_EQ(store->mount(), 0);
1872 ch = store->open_collection(cid);
1873 }
1874 {
1875 ObjectStore::Transaction t;
1876 std::string s(0x10000, 'c');
1877 bufferlist bl;
1878 bl.append(s);
1879 bl.append(s);
1880 bl.append(s);
1881 bl.append(s.substr(0, 0x10000-2));
1882 t.write(cid, hoid, 0, bl.length(), bl);
1883 cerr << "Yet another compressible write" << std::endl;
1884 r = queue_transaction(store, ch, std::move(t));
1885 ASSERT_EQ(r, 0);
1886 struct store_statfs_t statfs;
1887 r = store->statfs(&statfs);
1888 ASSERT_EQ(r, 0);
1889 ASSERT_EQ(0x40000 - 2, statfs.data_stored);
1890 ASSERT_EQ(0x30000, statfs.allocated);
1891 ASSERT_LE(statfs.data_compressed, 0x10000);
1892 ASSERT_EQ(0x20000, statfs.data_compressed_original);
1893 ASSERT_EQ(0x10000, statfs.data_compressed_allocated);
1894
1895 struct store_statfs_t statfs_pool;
1896 bool per_pool_omap;
1897 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1898 ASSERT_EQ(r, 0);
1899 ASSERT_EQ(0x40000 - 2, statfs_pool.data_stored);
1900 ASSERT_EQ(0x30000, statfs_pool.allocated);
1901 ASSERT_LE(statfs_pool.data_compressed, 0x10000);
1902 ASSERT_EQ(0x20000, statfs_pool.data_compressed_original);
1903 ASSERT_EQ(0x10000, statfs_pool.data_compressed_allocated);
1904 //force fsck
1905 ch.reset();
1906 EXPECT_EQ(store->umount(), 0);
1907 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
1908 EXPECT_EQ(store->mount(), 0);
1909 ch = store->open_collection(cid);
1910 }
1911 {
1912 struct store_statfs_t statfs;
1913 r = store->statfs(&statfs);
1914 ASSERT_EQ(r, 0);
1915
1916 struct store_statfs_t statfs_pool;
1917 bool per_pool_omap;
1918 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
1919 ASSERT_EQ(r, 0);
1920
1921 ObjectStore::Transaction t;
1922 t.clone(cid, hoid, hoid2);
1923 cerr << "Clone compressed objecte" << std::endl;
1924 r = queue_transaction(store, ch, std::move(t));
1925 ASSERT_EQ(r, 0);
1926 struct store_statfs_t statfs2;
1927 r = store->statfs(&statfs2);
1928 ASSERT_EQ(r, 0);
1929 ASSERT_GT(statfs2.data_stored, statfs.data_stored);
1930 ASSERT_EQ(statfs2.allocated, statfs.allocated);
1931 ASSERT_GT(statfs2.data_compressed, statfs.data_compressed);
1932 ASSERT_GT(statfs2.data_compressed_original, statfs.data_compressed_original);
1933 ASSERT_EQ(statfs2.data_compressed_allocated, statfs.data_compressed_allocated);
1934
1935 struct store_statfs_t statfs2_pool;
1936 r = store->pool_statfs(poolid, &statfs2_pool, &per_pool_omap);
1937 ASSERT_EQ(r, 0);
1938 ASSERT_GT(statfs2_pool.data_stored, statfs_pool.data_stored);
1939 ASSERT_EQ(statfs2_pool.allocated, statfs_pool.allocated);
1940 ASSERT_GT(statfs2_pool.data_compressed, statfs_pool.data_compressed);
1941 ASSERT_GT(statfs2_pool.data_compressed_original,
1942 statfs_pool.data_compressed_original);
1943 ASSERT_EQ(statfs2_pool.data_compressed_allocated,
1944 statfs_pool.data_compressed_allocated);
1945 }
1946
1947 {
1948 // verify no
1949 auto poolid2 = poolid + 1;
1950 coll_t cid2 = coll_t(spg_t(pg_t(20, poolid2), shard_id_t::NO_SHARD));
1951 ghobject_t hoid(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
1952 string(),
1953 0,
1954 poolid2,
1955 string()));
1956 auto ch = store->create_new_collection(cid2);
1957
1958 {
1959
1960 struct store_statfs_t statfs1_pool;
1961 bool per_pool_omap;
1962 int r = store->pool_statfs(poolid, &statfs1_pool, &per_pool_omap);
1963 ASSERT_EQ(r, 0);
1964
1965 cerr << "Creating second collection " << cid2 << std::endl;
1966 ObjectStore::Transaction t;
1967 t.create_collection(cid2, 0);
1968 r = queue_transaction(store, ch, std::move(t));
1969 ASSERT_EQ(r, 0);
1970
1971 t = ObjectStore::Transaction();
1972 bufferlist bl;
1973 bl.append("abcde");
1974 t.write(cid2, hoid, 0, 5, bl);
1975 r = queue_transaction(store, ch, std::move(t));
1976 ASSERT_EQ(r, 0);
1977
1978 struct store_statfs_t statfs2_pool;
1979 r = store->pool_statfs(poolid2, &statfs2_pool, &per_pool_omap);
1980 ASSERT_EQ(r, 0);
1981 ASSERT_EQ(5, statfs2_pool.data_stored);
1982 ASSERT_EQ(0x10000, statfs2_pool.allocated);
1983 ASSERT_EQ(0, statfs2_pool.data_compressed);
1984 ASSERT_EQ(0, statfs2_pool.data_compressed_original);
1985 ASSERT_EQ(0, statfs2_pool.data_compressed_allocated);
1986
1987 struct store_statfs_t statfs1_pool_again;
1988 r = store->pool_statfs(poolid, &statfs1_pool_again, &per_pool_omap);
1989 ASSERT_EQ(r, 0);
1990 // adjust 'available' since it has changed
1991 statfs1_pool_again.available = statfs1_pool.available;
1992 ASSERT_EQ(statfs1_pool_again, statfs1_pool);
1993
1994 t = ObjectStore::Transaction();
1995 t.remove(cid2, hoid);
1996 t.remove_collection(cid2);
1997 cerr << "Cleaning" << std::endl;
1998 r = queue_transaction(store, ch, std::move(t));
1999 ASSERT_EQ(r, 0);
2000 }
2001 }
2002
2003 {
2004 // verify ops on temporary object
2005
2006 auto poolid3 = poolid + 2;
2007 coll_t cid3 = coll_t(spg_t(pg_t(20, poolid3), shard_id_t::NO_SHARD));
2008 ghobject_t hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP),
2009 string(),
2010 0,
2011 poolid3,
2012 string()));
2013 ghobject_t hoid3_temp;
2014 hoid3_temp.hobj = hoid3.hobj.make_temp_hobject("Object 3 temp");
2015 auto ch3 = store->create_new_collection(cid3);
2016 {
2017 struct store_statfs_t statfs1_pool;
2018 bool per_pool_omap;
2019 int r = store->pool_statfs(poolid, &statfs1_pool, &per_pool_omap);
2020 ASSERT_EQ(r, 0);
2021
2022 cerr << "Creating third collection " << cid3 << std::endl;
2023 ObjectStore::Transaction t;
2024 t.create_collection(cid3, 0);
2025 r = queue_transaction(store, ch3, std::move(t));
2026 ASSERT_EQ(r, 0);
2027
2028 t = ObjectStore::Transaction();
2029 bufferlist bl;
2030 bl.append("abcde");
2031 t.write(cid3, hoid3_temp, 0, 5, bl);
2032 r = queue_transaction(store, ch3, std::move(t));
2033 ASSERT_EQ(r, 0);
2034
2035 struct store_statfs_t statfs3_pool;
2036 r = store->pool_statfs(poolid3, &statfs3_pool, &per_pool_omap);
2037 ASSERT_EQ(r, 0);
2038 ASSERT_EQ(5, statfs3_pool.data_stored);
2039 ASSERT_EQ(0x10000, statfs3_pool.allocated);
2040 ASSERT_EQ(0, statfs3_pool.data_compressed);
2041 ASSERT_EQ(0, statfs3_pool.data_compressed_original);
2042 ASSERT_EQ(0, statfs3_pool.data_compressed_allocated);
2043
2044 struct store_statfs_t statfs1_pool_again;
2045 r = store->pool_statfs(poolid, &statfs1_pool_again, &per_pool_omap);
2046 ASSERT_EQ(r, 0);
2047 // adjust 'available' since it has changed
2048 statfs1_pool_again.available = statfs1_pool.available;
2049 ASSERT_EQ(statfs1_pool_again, statfs1_pool);
2050
2051 //force fsck
2052 ch.reset();
2053 ch3.reset();
2054 EXPECT_EQ(store->umount(), 0);
2055 EXPECT_EQ(store->mount(), 0);
2056 ch = store->open_collection(cid);
2057 ch3 = store->open_collection(cid3);
2058
2059 t = ObjectStore::Transaction();
2060 t.collection_move_rename(
2061 cid3, hoid3_temp,
2062 cid3, hoid3);
2063 r = queue_transaction(store, ch3, std::move(t));
2064 ASSERT_EQ(r, 0);
2065
2066 struct store_statfs_t statfs3_pool_again;
2067 r = store->pool_statfs(poolid3, &statfs3_pool_again, &per_pool_omap);
2068 ASSERT_EQ(r, 0);
2069 ASSERT_EQ(statfs3_pool_again, statfs3_pool);
2070
2071 //force fsck
2072 ch.reset();
2073 ch3.reset();
2074 EXPECT_EQ(store->umount(), 0);
2075 EXPECT_EQ(store->mount(), 0);
2076 ch = store->open_collection(cid);
2077 ch3 = store->open_collection(cid3);
2078
2079 t = ObjectStore::Transaction();
2080 t.remove(cid3, hoid3);
2081 t.remove_collection(cid3);
2082 cerr << "Cleaning" << std::endl;
2083 r = queue_transaction(store, ch3, std::move(t));
2084 ASSERT_EQ(r, 0);
2085 }
2086 }
2087
2088 {
2089 ObjectStore::Transaction t;
2090 t.remove(cid, hoid);
2091 t.remove(cid, hoid2);
2092 t.remove_collection(cid);
2093 cerr << "Cleaning" << std::endl;
2094 r = queue_transaction(store, ch, std::move(t));
2095 ASSERT_EQ(r, 0);
2096
2097 struct store_statfs_t statfs;
2098 r = store->statfs(&statfs);
2099 ASSERT_EQ(r, 0);
2100 ASSERT_EQ( 0u, statfs.allocated);
2101 ASSERT_EQ( 0u, statfs.data_stored);
2102 ASSERT_EQ( 0u, statfs.data_compressed_original);
2103 ASSERT_EQ( 0u, statfs.data_compressed);
2104 ASSERT_EQ( 0u, statfs.data_compressed_allocated);
2105
2106 struct store_statfs_t statfs_pool;
2107 bool per_pool_omap;
2108 r = store->pool_statfs(poolid, &statfs_pool, &per_pool_omap);
2109 ASSERT_EQ(r, 0);
2110 ASSERT_EQ( 0u, statfs_pool.allocated);
2111 ASSERT_EQ( 0u, statfs_pool.data_stored);
2112 ASSERT_EQ( 0u, statfs_pool.data_compressed_original);
2113 ASSERT_EQ( 0u, statfs_pool.data_compressed);
2114 ASSERT_EQ( 0u, statfs_pool.data_compressed_allocated);
2115 }
2116 }
2117
2118 TEST_P(StoreTestSpecificAUSize, BluestoreFragmentedBlobTest) {
2119 if(string(GetParam()) != "bluestore")
2120 return;
2121 if (smr) {
2122 cout << "TODO: fix this for smr" << std::endl;
2123 return;
2124 }
2125 SetVal(g_conf(), "bluestore_block_db_path", "");
2126 StartDeferred(0x10000);
2127
2128 int r;
2129 coll_t cid;
2130 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2131 auto ch = store->create_new_collection(cid);
2132 {
2133 ObjectStore::Transaction t;
2134 t.create_collection(cid, 0);
2135 cerr << "Creating collection " << cid << std::endl;
2136 r = queue_transaction(store, ch, std::move(t));
2137 ASSERT_EQ(r, 0);
2138 }
2139 {
2140 bool exists = store->exists(ch, hoid);
2141 ASSERT_TRUE(!exists);
2142
2143 ObjectStore::Transaction t;
2144 t.touch(cid, hoid);
2145 cerr << "Creating object " << hoid << std::endl;
2146 r = queue_transaction(store, ch, std::move(t));
2147 ASSERT_EQ(r, 0);
2148
2149 exists = store->exists(ch, hoid);
2150 ASSERT_EQ(true, exists);
2151 }
2152 {
2153 struct store_statfs_t statfs;
2154 int r = store->statfs(&statfs);
2155 ASSERT_EQ(r, 0);
2156 ASSERT_EQ(g_conf()->bluestore_block_size, statfs.total);
2157 ASSERT_EQ(0u, statfs.allocated);
2158 ASSERT_EQ(0u, statfs.data_stored);
2159 ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf()->bluestore_block_size);
2160 }
2161 std::string data;
2162 data.resize(0x10000 * 3);
2163 {
2164 ObjectStore::Transaction t;
2165 for(size_t i = 0;i < data.size(); i++)
2166 data[i] = i / 256 + 1;
2167 bufferlist bl, newdata;
2168 bl.append(data);
2169 t.write(cid, hoid, 0, bl.length(), bl);
2170 t.zero(cid, hoid, 0x10000, 0x10000);
2171 cerr << "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl;
2172 r = queue_transaction(store, ch, std::move(t));
2173 ASSERT_EQ(r, 0);
2174
2175 struct store_statfs_t statfs;
2176 int r = store->statfs(&statfs);
2177 ASSERT_EQ(r, 0);
2178 ASSERT_EQ(0x20000, statfs.data_stored);
2179 ASSERT_EQ(0x20000, statfs.allocated);
2180
2181 r = store->read(ch, hoid, 0, data.size(), newdata);
2182 ASSERT_EQ(r, (int)data.size());
2183 {
2184 bufferlist expected;
2185 expected.append(data.substr(0, 0x10000));
2186 expected.append(string(0x10000, 0));
2187 expected.append(data.substr(0x20000, 0x10000));
2188 ASSERT_TRUE(bl_eq(expected, newdata));
2189 }
2190 newdata.clear();
2191
2192 r = store->read(ch, hoid, 1, data.size()-2, newdata);
2193 ASSERT_EQ(r, (int)data.size()-2);
2194 {
2195 bufferlist expected;
2196 expected.append(data.substr(1, 0x10000-1));
2197 expected.append(string(0x10000, 0));
2198 expected.append(data.substr(0x20000, 0x10000 - 1));
2199 ASSERT_TRUE(bl_eq(expected, newdata));
2200 }
2201 newdata.clear();
2202 }
2203 //force fsck
2204 ch.reset();
2205 EXPECT_EQ(store->umount(), 0);
2206 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
2207 EXPECT_EQ(store->mount(), 0);
2208 ch = store->open_collection(cid);
2209
2210 {
2211 ObjectStore::Transaction t;
2212 std::string data2(3, 'b');
2213 bufferlist bl, newdata;
2214 bl.append(data2);
2215 t.write(cid, hoid, 0x20000, bl.length(), bl);
2216 cerr << "Write 3 bytes after the hole" << std::endl;
2217 r = queue_transaction(store, ch, std::move(t));
2218 ASSERT_EQ(r, 0);
2219
2220 struct store_statfs_t statfs;
2221 int r = store->statfs(&statfs);
2222 ASSERT_EQ(r, 0);
2223 ASSERT_EQ(0x20000, statfs.allocated);
2224 ASSERT_EQ(0x20000, statfs.data_stored);
2225
2226 r = store->read(ch, hoid, 0x20000-1, 21, newdata);
2227 ASSERT_EQ(r, (int)21);
2228 {
2229 bufferlist expected;
2230 expected.append(string(0x1, 0));
2231 expected.append(string(data2));
2232 expected.append(data.substr(0x20003, 21-4));
2233 ASSERT_TRUE(bl_eq(expected, newdata));
2234 }
2235 newdata.clear();
2236 }
2237 //force fsck
2238 ch.reset();
2239 EXPECT_EQ(store->umount(), 0);
2240 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
2241 EXPECT_EQ(store->mount(), 0);
2242 ch = store->open_collection(cid);
2243
2244 {
2245 ObjectStore::Transaction t;
2246 std::string data2(3, 'a');
2247 bufferlist bl, newdata;
2248 bl.append(data2);
2249 t.write(cid, hoid, 0x10000+1, bl.length(), bl);
2250 cerr << "Write 3 bytes to the hole" << std::endl;
2251 r = queue_transaction(store, ch, std::move(t));
2252 ASSERT_EQ(r, 0);
2253
2254 struct store_statfs_t statfs;
2255 int r = store->statfs(&statfs);
2256 ASSERT_EQ(r, 0);
2257 ASSERT_EQ(0x30000, statfs.allocated);
2258 ASSERT_EQ(0x20003, statfs.data_stored);
2259
2260 r = store->read(ch, hoid, 0x10000-1, 0x10000+22, newdata);
2261 ASSERT_EQ(r, (int)0x10000+22);
2262 {
2263 bufferlist expected;
2264 expected.append(data.substr(0x10000-1, 1));
2265 expected.append(string(0x1, 0));
2266 expected.append(data2);
2267 expected.append(string(0x10000-4, 0));
2268 expected.append(string(0x3, 'b'));
2269 expected.append(data.substr(0x20004, 21-3));
2270 ASSERT_TRUE(bl_eq(expected, newdata));
2271 }
2272 newdata.clear();
2273 }
2274 {
2275 ObjectStore::Transaction t;
2276 bufferlist bl, newdata;
2277 bl.append(string(0x30000, 'c'));
2278 t.write(cid, hoid, 0, 0x30000, bl);
2279 t.zero(cid, hoid, 0, 0x10000);
2280 t.zero(cid, hoid, 0x20000, 0x10000);
2281 cerr << "Rewrite an object and create two holes at the beginning and the end" << std::endl;
2282 r = queue_transaction(store, ch, std::move(t));
2283 ASSERT_EQ(r, 0);
2284
2285 struct store_statfs_t statfs;
2286 int r = store->statfs(&statfs);
2287 ASSERT_EQ(r, 0);
2288 ASSERT_EQ(0x10000, statfs.allocated);
2289 ASSERT_EQ(0x10000, statfs.data_stored);
2290
2291 r = store->read(ch, hoid, 0, 0x30000, newdata);
2292 ASSERT_EQ(r, (int)0x30000);
2293 {
2294 bufferlist expected;
2295 expected.append(string(0x10000, 0));
2296 expected.append(string(0x10000, 'c'));
2297 expected.append(string(0x10000, 0));
2298 ASSERT_TRUE(bl_eq(expected, newdata));
2299 }
2300 newdata.clear();
2301 }
2302
2303 //force fsck
2304 ch.reset();
2305 EXPECT_EQ(store->umount(), 0);
2306 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
2307 EXPECT_EQ(store->mount(), 0);
2308 ch = store->open_collection(cid);
2309
2310 {
2311 ObjectStore::Transaction t;
2312 t.remove(cid, hoid);
2313 t.remove_collection(cid);
2314 cerr << "Cleaning" << std::endl;
2315 r = queue_transaction(store, ch, std::move(t));
2316 ASSERT_EQ(r, 0);
2317
2318 struct store_statfs_t statfs;
2319 r = store->statfs(&statfs);
2320 ASSERT_EQ(r, 0);
2321 ASSERT_EQ( 0u, statfs.allocated);
2322 ASSERT_EQ( 0u, statfs.data_stored);
2323 ASSERT_EQ( 0u, statfs.data_compressed_original);
2324 ASSERT_EQ( 0u, statfs.data_compressed);
2325 ASSERT_EQ( 0u, statfs.data_compressed_allocated);
2326 }
2327 }
2328 #endif
2329
2330 TEST_P(StoreTest, ManySmallWrite) {
2331 int r;
2332 coll_t cid;
2333 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2334 ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
2335 auto ch = store->create_new_collection(cid);
2336 {
2337 ObjectStore::Transaction t;
2338 t.create_collection(cid, 0);
2339 cerr << "Creating collection " << cid << std::endl;
2340 r = queue_transaction(store, ch, std::move(t));
2341 ASSERT_EQ(r, 0);
2342 }
2343 bufferlist bl;
2344 bufferptr bp(4096);
2345 bp.zero();
2346 bl.append(bp);
2347 for (int i=0; i<100; ++i) {
2348 ObjectStore::Transaction t;
2349 t.write(cid, a, i*4096, 4096, bl, 0);
2350 r = queue_transaction(store, ch, std::move(t));
2351 ASSERT_EQ(r, 0);
2352 }
2353 for (int i=0; i<100; ++i) {
2354 ObjectStore::Transaction t;
2355 t.write(cid, b, (rand() % 1024)*4096, 4096, bl, 0);
2356 r = queue_transaction(store, ch, std::move(t));
2357 ASSERT_EQ(r, 0);
2358 }
2359 {
2360 ObjectStore::Transaction t;
2361 t.remove(cid, a);
2362 t.remove(cid, b);
2363 t.remove_collection(cid);
2364 cerr << "Cleaning" << std::endl;
2365 r = queue_transaction(store, ch, std::move(t));
2366 ASSERT_EQ(r, 0);
2367 }
2368 }
2369
2370 TEST_P(StoreTest, MultiSmallWriteSameBlock) {
2371 int r;
2372 coll_t cid;
2373 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2374 auto ch = store->create_new_collection(cid);
2375 {
2376 ObjectStore::Transaction t;
2377 t.create_collection(cid, 0);
2378 cerr << "Creating collection " << cid << std::endl;
2379 r = queue_transaction(store, ch, std::move(t));
2380 ASSERT_EQ(r, 0);
2381 }
2382 bufferlist bl;
2383 bl.append("short");
2384 C_SaferCond c, d;
2385 // touch same block in both same transaction, tls, and pipelined txns
2386 {
2387 ObjectStore::Transaction t, u;
2388 t.write(cid, a, 0, 5, bl, 0);
2389 t.write(cid, a, 5, 5, bl, 0);
2390 t.write(cid, a, 4094, 5, bl, 0);
2391 t.write(cid, a, 9000, 5, bl, 0);
2392 u.write(cid, a, 10, 5, bl, 0);
2393 u.write(cid, a, 7000, 5, bl, 0);
2394 t.register_on_commit(&c);
2395 vector<ObjectStore::Transaction> v = {t, u};
2396 store->queue_transactions(ch, v);
2397 }
2398 {
2399 ObjectStore::Transaction t, u;
2400 t.write(cid, a, 40, 5, bl, 0);
2401 t.write(cid, a, 45, 5, bl, 0);
2402 t.write(cid, a, 4094, 5, bl, 0);
2403 t.write(cid, a, 6000, 5, bl, 0);
2404 u.write(cid, a, 610, 5, bl, 0);
2405 u.write(cid, a, 11000, 5, bl, 0);
2406 t.register_on_commit(&d);
2407 vector<ObjectStore::Transaction> v = {t, u};
2408 store->queue_transactions(ch, v);
2409 }
2410 c.wait();
2411 d.wait();
2412 {
2413 bufferlist bl2;
2414 r = store->read(ch, a, 0, 16000, bl2);
2415 ASSERT_GE(r, 0);
2416 }
2417 {
2418 ObjectStore::Transaction t;
2419 t.remove(cid, a);
2420 t.remove_collection(cid);
2421 cerr << "Cleaning" << std::endl;
2422 r = queue_transaction(store, ch, std::move(t));
2423 ASSERT_EQ(r, 0);
2424 }
2425 }
2426
2427 TEST_P(StoreTest, SmallSkipFront) {
2428 int r;
2429 coll_t cid;
2430 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2431 auto ch = store->create_new_collection(cid);
2432 {
2433 ObjectStore::Transaction t;
2434 t.create_collection(cid, 0);
2435 cerr << "Creating collection " << cid << std::endl;
2436 r = queue_transaction(store, ch, std::move(t));
2437 ASSERT_EQ(r, 0);
2438 }
2439 {
2440 ObjectStore::Transaction t;
2441 t.touch(cid, a);
2442 t.truncate(cid, a, 3000);
2443 r = queue_transaction(store, ch, std::move(t));
2444 ASSERT_EQ(r, 0);
2445 }
2446 {
2447 bufferlist bl;
2448 bufferptr bp(4096);
2449 memset(bp.c_str(), 1, 4096);
2450 bl.append(bp);
2451 ObjectStore::Transaction t;
2452 t.write(cid, a, 4096, 4096, bl);
2453 r = queue_transaction(store, ch, std::move(t));
2454 ASSERT_EQ(r, 0);
2455 }
2456 {
2457 bufferlist bl;
2458 ASSERT_EQ(8192, store->read(ch, a, 0, 8192, bl));
2459 for (unsigned i=0; i<4096; ++i)
2460 ASSERT_EQ(0, bl[i]);
2461 for (unsigned i=4096; i<8192; ++i)
2462 ASSERT_EQ(1, bl[i]);
2463 }
2464 {
2465 ObjectStore::Transaction t;
2466 t.remove(cid, a);
2467 t.remove_collection(cid);
2468 cerr << "Cleaning" << std::endl;
2469 r = queue_transaction(store, ch, std::move(t));
2470 ASSERT_EQ(r, 0);
2471 }
2472 }
2473
2474 TEST_P(StoreTest, AppendDeferredVsTailCache) {
2475 int r;
2476 coll_t cid;
2477 ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
2478 auto ch = store->create_new_collection(cid);
2479 {
2480 ObjectStore::Transaction t;
2481 t.create_collection(cid, 0);
2482 cerr << "Creating collection " << cid << std::endl;
2483 r = store->queue_transaction(ch, std::move(t));
2484 ASSERT_EQ(r, 0);
2485 }
2486 unsigned min_alloc = g_conf()->bluestore_min_alloc_size;
2487 unsigned size = min_alloc / 3;
2488 bufferptr bpa(size);
2489 memset(bpa.c_str(), 1, bpa.length());
2490 bufferlist bla;
2491 bla.append(bpa);
2492 {
2493 ObjectStore::Transaction t;
2494 t.write(cid, a, 0, bla.length(), bla, 0);
2495 r = store->queue_transaction(ch, std::move(t));
2496 ASSERT_EQ(r, 0);
2497 }
2498
2499 // force cached tail to clear ...
2500 {
2501 ch.reset();
2502 int r = store->umount();
2503 ASSERT_EQ(0, r);
2504 r = store->mount();
2505 ASSERT_EQ(0, r);
2506 ch = store->open_collection(cid);
2507 }
2508
2509 bufferptr bpb(size);
2510 memset(bpb.c_str(), 2, bpb.length());
2511 bufferlist blb;
2512 blb.append(bpb);
2513 {
2514 ObjectStore::Transaction t;
2515 t.write(cid, a, bla.length(), blb.length(), blb, 0);
2516 r = store->queue_transaction(ch, std::move(t));
2517 ASSERT_EQ(r, 0);
2518 }
2519 bufferptr bpc(size);
2520 memset(bpc.c_str(), 3, bpc.length());
2521 bufferlist blc;
2522 blc.append(bpc);
2523 {
2524 ObjectStore::Transaction t;
2525 t.write(cid, a, bla.length() + blb.length(), blc.length(), blc, 0);
2526 r = store->queue_transaction(ch, std::move(t));
2527 ASSERT_EQ(r, 0);
2528 }
2529 bufferlist final;
2530 final.append(bla);
2531 final.append(blb);
2532 final.append(blc);
2533 bufferlist actual;
2534 {
2535 ASSERT_EQ((int)final.length(),
2536 store->read(ch, a, 0, final.length(), actual));
2537 ASSERT_TRUE(bl_eq(final, actual));
2538 }
2539 {
2540 ObjectStore::Transaction t;
2541 t.remove(cid, a);
2542 t.remove_collection(cid);
2543 cerr << "Cleaning" << std::endl;
2544 r = store->queue_transaction(ch, std::move(t));
2545 ASSERT_EQ(r, 0);
2546 }
2547 }
2548
2549 TEST_P(StoreTest, AppendZeroTrailingSharedBlock) {
2550 int r;
2551 coll_t cid;
2552 ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
2553 ghobject_t b = a;
2554 b.hobj.snap = 1;
2555 auto ch = store->create_new_collection(cid);
2556 {
2557 ObjectStore::Transaction t;
2558 t.create_collection(cid, 0);
2559 cerr << "Creating collection " << cid << std::endl;
2560 r = store->queue_transaction(ch, std::move(t));
2561 ASSERT_EQ(r, 0);
2562 }
2563 unsigned min_alloc = g_conf()->bluestore_min_alloc_size;
2564 unsigned size = min_alloc / 3;
2565 bufferptr bpa(size);
2566 memset(bpa.c_str(), 1, bpa.length());
2567 bufferlist bla;
2568 bla.append(bpa);
2569 // make sure there is some trailing gunk in the last block
2570 {
2571 bufferlist bt;
2572 bt.append(bla);
2573 bt.append("BADBADBADBAD");
2574 ObjectStore::Transaction t;
2575 t.write(cid, a, 0, bt.length(), bt, 0);
2576 r = store->queue_transaction(ch, std::move(t));
2577 ASSERT_EQ(r, 0);
2578 }
2579 {
2580 ObjectStore::Transaction t;
2581 t.truncate(cid, a, size);
2582 r = store->queue_transaction(ch, std::move(t));
2583 ASSERT_EQ(r, 0);
2584 }
2585
2586 // clone
2587 {
2588 ObjectStore::Transaction t;
2589 t.clone(cid, a, b);
2590 r = store->queue_transaction(ch, std::move(t));
2591 ASSERT_EQ(r, 0);
2592 }
2593
2594 // append with implicit zeroing
2595 bufferptr bpb(size);
2596 memset(bpb.c_str(), 2, bpb.length());
2597 bufferlist blb;
2598 blb.append(bpb);
2599 {
2600 ObjectStore::Transaction t;
2601 t.write(cid, a, min_alloc * 3, blb.length(), blb, 0);
2602 r = store->queue_transaction(ch, std::move(t));
2603 ASSERT_EQ(r, 0);
2604 }
2605 bufferlist final;
2606 final.append(bla);
2607 bufferlist zeros;
2608 zeros.append_zero(min_alloc * 3 - size);
2609 final.append(zeros);
2610 final.append(blb);
2611 bufferlist actual;
2612 {
2613 ASSERT_EQ((int)final.length(),
2614 store->read(ch, a, 0, final.length(), actual));
2615 final.hexdump(cout);
2616 actual.hexdump(cout);
2617 ASSERT_TRUE(bl_eq(final, actual));
2618 }
2619 {
2620 ObjectStore::Transaction t;
2621 t.remove(cid, a);
2622 t.remove(cid, b);
2623 t.remove_collection(cid);
2624 cerr << "Cleaning" << std::endl;
2625 r = store->queue_transaction(ch, std::move(t));
2626 ASSERT_EQ(r, 0);
2627 }
2628 }
2629
2630 TEST_P(StoreTest, SmallSequentialUnaligned) {
2631 int r;
2632 coll_t cid;
2633 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2634 auto ch = store->create_new_collection(cid);
2635 {
2636 ObjectStore::Transaction t;
2637 t.create_collection(cid, 0);
2638 cerr << "Creating collection " << cid << std::endl;
2639 r = queue_transaction(store, ch, std::move(t));
2640 ASSERT_EQ(r, 0);
2641 }
2642 bufferlist bl;
2643 int len = 1000;
2644 bufferptr bp(len);
2645 bp.zero();
2646 bl.append(bp);
2647 for (int i=0; i<1000; ++i) {
2648 ObjectStore::Transaction t;
2649 t.write(cid, a, i*len, len, bl, 0);
2650 r = queue_transaction(store, ch, std::move(t));
2651 ASSERT_EQ(r, 0);
2652 }
2653 {
2654 ObjectStore::Transaction t;
2655 t.remove(cid, a);
2656 t.remove_collection(cid);
2657 cerr << "Cleaning" << std::endl;
2658 r = queue_transaction(store, ch, std::move(t));
2659 ASSERT_EQ(r, 0);
2660 }
2661 }
2662
2663 TEST_P(StoreTest, ManyBigWrite) {
2664 int r;
2665 coll_t cid;
2666 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2667 ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
2668 auto ch = store->create_new_collection(cid);
2669 {
2670 ObjectStore::Transaction t;
2671 t.create_collection(cid, 0);
2672 cerr << "Creating collection " << cid << std::endl;
2673 r = queue_transaction(store, ch, std::move(t));
2674 ASSERT_EQ(r, 0);
2675 }
2676 bufferlist bl;
2677 bufferptr bp(4 * 1048576);
2678 bp.zero();
2679 bl.append(bp);
2680 for (int i=0; i<10; ++i) {
2681 ObjectStore::Transaction t;
2682 t.write(cid, a, i*4*1048586, 4*1048576, bl, 0);
2683 r = queue_transaction(store, ch, std::move(t));
2684 ASSERT_EQ(r, 0);
2685 }
2686 // aligned
2687 for (int i=0; i<10; ++i) {
2688 ObjectStore::Transaction t;
2689 t.write(cid, b, (rand() % 256)*4*1048576, 4*1048576, bl, 0);
2690 r = queue_transaction(store, ch, std::move(t));
2691 ASSERT_EQ(r, 0);
2692 }
2693 // unaligned
2694 for (int i=0; i<10; ++i) {
2695 ObjectStore::Transaction t;
2696 t.write(cid, b, (rand() % (256*4096))*1024, 4*1048576, bl, 0);
2697 r = queue_transaction(store, ch, std::move(t));
2698 ASSERT_EQ(r, 0);
2699 }
2700 // do some zeros
2701 for (int i=0; i<10; ++i) {
2702 ObjectStore::Transaction t;
2703 t.zero(cid, b, (rand() % (256*4096))*1024, 16*1048576);
2704 r = queue_transaction(store, ch, std::move(t));
2705 ASSERT_EQ(r, 0);
2706 }
2707 {
2708 ObjectStore::Transaction t;
2709 t.remove(cid, a);
2710 t.remove(cid, b);
2711 t.remove_collection(cid);
2712 cerr << "Cleaning" << std::endl;
2713 r = queue_transaction(store, ch, std::move(t));
2714 ASSERT_EQ(r, 0);
2715 }
2716 }
2717
2718 TEST_P(StoreTest, BigWriteBigZero) {
2719 int r;
2720 coll_t cid;
2721 ghobject_t a(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2722 auto ch = store->create_new_collection(cid);
2723 {
2724 ObjectStore::Transaction t;
2725 t.create_collection(cid, 0);
2726 r = queue_transaction(store, ch, std::move(t));
2727 ASSERT_EQ(r, 0);
2728 }
2729 bufferlist bl;
2730 bufferptr bp(1048576);
2731 memset(bp.c_str(), 'b', bp.length());
2732 bl.append(bp);
2733 bufferlist s;
2734 bufferptr sp(4096);
2735 memset(sp.c_str(), 's', sp.length());
2736 s.append(sp);
2737 {
2738 ObjectStore::Transaction t;
2739 t.write(cid, a, 0, bl.length(), bl);
2740 r = queue_transaction(store, ch, std::move(t));
2741 ASSERT_EQ(r, 0);
2742 }
2743 {
2744 ObjectStore::Transaction t;
2745 t.zero(cid, a, bl.length() / 4, bl.length() / 2);
2746 r = queue_transaction(store, ch, std::move(t));
2747 ASSERT_EQ(r, 0);
2748 }
2749 {
2750 ObjectStore::Transaction t;
2751 t.write(cid, a, bl.length() / 2, s.length(), s);
2752 r = queue_transaction(store, ch, std::move(t));
2753 ASSERT_EQ(r, 0);
2754 }
2755 {
2756 ObjectStore::Transaction t;
2757 t.remove(cid, a);
2758 t.remove_collection(cid);
2759 r = queue_transaction(store, ch, std::move(t));
2760 ASSERT_EQ(r, 0);
2761 }
2762 }
2763
2764 TEST_P(StoreTest, MiscFragmentTests) {
2765 int r;
2766 coll_t cid;
2767 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2768 auto ch = store->create_new_collection(cid);
2769 {
2770 ObjectStore::Transaction t;
2771 t.create_collection(cid, 0);
2772 cerr << "Creating collection " << cid << std::endl;
2773 r = queue_transaction(store, ch, std::move(t));
2774 ASSERT_EQ(r, 0);
2775 }
2776 bufferlist bl;
2777 bufferptr bp(524288);
2778 bp.zero();
2779 bl.append(bp);
2780 {
2781 ObjectStore::Transaction t;
2782 t.write(cid, a, 0, 524288, bl, 0);
2783 r = queue_transaction(store, ch, std::move(t));
2784 ASSERT_EQ(r, 0);
2785 }
2786 {
2787 ObjectStore::Transaction t;
2788 t.write(cid, a, 1048576, 524288, bl, 0);
2789 r = queue_transaction(store, ch, std::move(t));
2790 ASSERT_EQ(r, 0);
2791 }
2792 {
2793 bufferlist inbl;
2794 int r = store->read(ch, a, 524288 + 131072, 1024, inbl);
2795 ASSERT_EQ(r, 1024);
2796 ASSERT_EQ(inbl.length(), 1024u);
2797 ASSERT_TRUE(inbl.is_zero());
2798 }
2799 {
2800 ObjectStore::Transaction t;
2801 t.write(cid, a, 1048576 - 4096, 524288, bl, 0);
2802 r = queue_transaction(store, ch, std::move(t));
2803 ASSERT_EQ(r, 0);
2804 }
2805 {
2806 ObjectStore::Transaction t;
2807 t.remove(cid, a);
2808 t.remove_collection(cid);
2809 cerr << "Cleaning" << std::endl;
2810 r = queue_transaction(store, ch, std::move(t));
2811 ASSERT_EQ(r, 0);
2812 }
2813
2814 }
2815
2816 TEST_P(StoreTest, ZeroVsObjectSize) {
2817 int r;
2818 coll_t cid;
2819 struct stat stat;
2820 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2821 auto ch = store->create_new_collection(cid);
2822 {
2823 ObjectStore::Transaction t;
2824 t.create_collection(cid, 0);
2825 cerr << "Creating collection " << cid << std::endl;
2826 r = queue_transaction(store, ch, std::move(t));
2827 ASSERT_EQ(r, 0);
2828 }
2829 bufferlist a;
2830 a.append("stuff");
2831 {
2832 ObjectStore::Transaction t;
2833 t.write(cid, hoid, 0, 5, a);
2834 r = queue_transaction(store, ch, std::move(t));
2835 ASSERT_EQ(r, 0);
2836 }
2837 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2838 ASSERT_EQ(5, stat.st_size);
2839 {
2840 ObjectStore::Transaction t;
2841 t.zero(cid, hoid, 1, 2);
2842 r = queue_transaction(store, ch, std::move(t));
2843 ASSERT_EQ(r, 0);
2844 }
2845 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2846 ASSERT_EQ(5, stat.st_size);
2847 {
2848 ObjectStore::Transaction t;
2849 t.zero(cid, hoid, 3, 200);
2850 r = queue_transaction(store, ch, std::move(t));
2851 ASSERT_EQ(r, 0);
2852 }
2853 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2854 ASSERT_EQ(203, stat.st_size);
2855 {
2856 ObjectStore::Transaction t;
2857 t.zero(cid, hoid, 100000, 200);
2858 r = queue_transaction(store, ch, std::move(t));
2859 ASSERT_EQ(r, 0);
2860 }
2861 ASSERT_EQ(0, store->stat(ch, hoid, &stat));
2862 ASSERT_EQ(100200, stat.st_size);
2863 }
2864
2865 TEST_P(StoreTest, ZeroLengthWrite) {
2866 int r;
2867 coll_t cid;
2868 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2869 auto ch = store->create_new_collection(cid);
2870 {
2871 ObjectStore::Transaction t;
2872 t.create_collection(cid, 0);
2873 t.touch(cid, hoid);
2874 r = queue_transaction(store, ch, std::move(t));
2875 ASSERT_EQ(r, 0);
2876 }
2877 {
2878 ObjectStore::Transaction t;
2879 bufferlist empty;
2880 t.write(cid, hoid, 1048576, 0, empty);
2881 r = queue_transaction(store, ch, std::move(t));
2882 ASSERT_EQ(r, 0);
2883 }
2884 struct stat stat;
2885 r = store->stat(ch, hoid, &stat);
2886 ASSERT_EQ(0, r);
2887 ASSERT_EQ(0, stat.st_size);
2888
2889 bufferlist newdata;
2890 r = store->read(ch, hoid, 0, 1048576, newdata);
2891 ASSERT_EQ(0, r);
2892 }
2893
2894 TEST_P(StoreTest, ZeroLengthZero) {
2895 int r;
2896 coll_t cid;
2897 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2898 auto ch = store->create_new_collection(cid);
2899 {
2900 ObjectStore::Transaction t;
2901 t.create_collection(cid, 0);
2902 t.touch(cid, hoid);
2903 r = queue_transaction(store, ch, std::move(t));
2904 ASSERT_EQ(0, r);
2905 }
2906 {
2907 ObjectStore::Transaction t;
2908 t.zero(cid, hoid, 1048576, 0);
2909 r = queue_transaction(store, ch, std::move(t));
2910 ASSERT_EQ(0, r);
2911 }
2912 struct stat stat;
2913 r = store->stat(ch, hoid, &stat);
2914 ASSERT_EQ(0, r);
2915 ASSERT_EQ(0, stat.st_size);
2916
2917 bufferlist newdata;
2918 r = store->read(ch, hoid, 0, 1048576, newdata);
2919 ASSERT_EQ(0, r);
2920 }
2921
2922 TEST_P(StoreTest, SimpleAttrTest) {
2923 int r;
2924 coll_t cid;
2925 ghobject_t hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP)));
2926 bufferlist val, val2;
2927 val.append("value");
2928 val.append("value2");
2929 {
2930 auto ch = store->open_collection(cid);
2931 ASSERT_FALSE(ch);
2932 }
2933 auto ch = store->create_new_collection(cid);
2934 {
2935 ObjectStore::Transaction t;
2936 t.create_collection(cid, 0);
2937 r = queue_transaction(store, ch, std::move(t));
2938 ASSERT_EQ(r, 0);
2939 }
2940 {
2941 bool empty;
2942 int r = store->collection_empty(ch, &empty);
2943 ASSERT_EQ(0, r);
2944 ASSERT_TRUE(empty);
2945 }
2946 {
2947 bufferptr bp;
2948 r = store->getattr(ch, hoid, "nofoo", bp);
2949 ASSERT_EQ(-ENOENT, r);
2950 }
2951 {
2952 ObjectStore::Transaction t;
2953 t.touch(cid, hoid);
2954 t.setattr(cid, hoid, "foo", val);
2955 t.setattr(cid, hoid, "bar", val2);
2956 r = queue_transaction(store, ch, std::move(t));
2957 ASSERT_EQ(r, 0);
2958 }
2959 {
2960 bool empty;
2961 int r = store->collection_empty(ch, &empty);
2962 ASSERT_EQ(0, r);
2963 ASSERT_TRUE(!empty);
2964 }
2965 {
2966 bufferptr bp;
2967 r = store->getattr(ch, hoid, "nofoo", bp);
2968 ASSERT_EQ(-ENODATA, r);
2969
2970 r = store->getattr(ch, hoid, "foo", bp);
2971 ASSERT_EQ(0, r);
2972 bufferlist bl;
2973 bl.append(bp);
2974 ASSERT_TRUE(bl_eq(val, bl));
2975
2976 map<string,bufferptr,less<>> bm;
2977 r = store->getattrs(ch, hoid, bm);
2978 ASSERT_EQ(0, r);
2979
2980 }
2981 {
2982 ObjectStore::Transaction t;
2983 t.remove(cid, hoid);
2984 t.remove_collection(cid);
2985 r = queue_transaction(store, ch, std::move(t));
2986 ASSERT_EQ(r, 0);
2987 }
2988 }
2989
2990 TEST_P(StoreTest, SimpleListTest) {
2991 int r;
2992 coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2993 auto ch = store->create_new_collection(cid);
2994 {
2995 ObjectStore::Transaction t;
2996 t.create_collection(cid, 0);
2997 cerr << "Creating collection " << cid << std::endl;
2998 r = queue_transaction(store, ch, std::move(t));
2999 ASSERT_EQ(r, 0);
3000 }
3001 set<ghobject_t> all;
3002 {
3003 ObjectStore::Transaction t;
3004 for (int i=0; i<200; ++i) {
3005 string name("object_");
3006 name += stringify(i);
3007 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
3008 ghobject_t::NO_GEN, shard_id_t(1));
3009 hoid.hobj.pool = 1;
3010 all.insert(hoid);
3011 t.touch(cid, hoid);
3012 cerr << "Creating object " << hoid << std::endl;
3013 }
3014 r = queue_transaction(store, ch, std::move(t));
3015 ASSERT_EQ(r, 0);
3016 }
3017 {
3018 set<ghobject_t> saw;
3019 vector<ghobject_t> objects;
3020 ghobject_t next, current;
3021 while (!next.is_max()) {
3022 int r = collection_list(store, ch, current, ghobject_t::get_max(), 50,
3023 &objects, &next);
3024 ASSERT_EQ(r, 0);
3025 ASSERT_TRUE(sorted(objects));
3026 cout << " got " << objects.size() << " next " << next << std::endl;
3027 for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
3028 ++p) {
3029 if (saw.count(*p)) {
3030 cout << "got DUP " << *p << std::endl;
3031 } else {
3032 //cout << "got new " << *p << std::endl;
3033 }
3034 saw.insert(*p);
3035 }
3036 objects.clear();
3037 current = next;
3038 }
3039 ASSERT_EQ(saw.size(), all.size());
3040 ASSERT_EQ(saw, all);
3041 }
3042 {
3043 ObjectStore::Transaction t;
3044 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
3045 t.remove(cid, *p);
3046 t.remove_collection(cid);
3047 cerr << "Cleaning" << std::endl;
3048 r = queue_transaction(store, ch, std::move(t));
3049 ASSERT_EQ(r, 0);
3050 }
3051 }
3052
3053 TEST_P(StoreTest, ListEndTest) {
3054 int r;
3055 coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
3056 auto ch = store->create_new_collection(cid);
3057 {
3058 ObjectStore::Transaction t;
3059 t.create_collection(cid, 0);
3060 cerr << "Creating collection " << cid << std::endl;
3061 r = queue_transaction(store, ch, std::move(t));
3062 ASSERT_EQ(r, 0);
3063 }
3064 set<ghobject_t> all;
3065 {
3066 ObjectStore::Transaction t;
3067 for (int i=0; i<200; ++i) {
3068 string name("object_");
3069 name += stringify(i);
3070 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
3071 ghobject_t::NO_GEN, shard_id_t(1));
3072 hoid.hobj.pool = 1;
3073 all.insert(hoid);
3074 t.touch(cid, hoid);
3075 cerr << "Creating object " << hoid << std::endl;
3076 }
3077 r = queue_transaction(store, ch, std::move(t));
3078 ASSERT_EQ(r, 0);
3079 }
3080 {
3081 ghobject_t end(hobject_t(sobject_t("object_100", CEPH_NOSNAP)),
3082 ghobject_t::NO_GEN, shard_id_t(1));
3083 end.hobj.pool = 1;
3084 vector<ghobject_t> objects;
3085 ghobject_t next;
3086 int r = collection_list(store, ch, ghobject_t(), end, 500, &objects, &next);
3087 ASSERT_EQ(r, 0);
3088 for (auto &p : objects) {
3089 ASSERT_NE(p, end);
3090 }
3091 }
3092 {
3093 ObjectStore::Transaction t;
3094 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
3095 t.remove(cid, *p);
3096 t.remove_collection(cid);
3097 cerr << "Cleaning" << std::endl;
3098 r = queue_transaction(store, ch, std::move(t));
3099 ASSERT_EQ(r, 0);
3100 }
3101 }
3102
3103 TEST_P(StoreTest, List_0xfffffff_Hash_Test_in_meta) {
3104 int r = 0;
3105 coll_t cid;
3106 auto ch = store->create_new_collection(cid);
3107 {
3108 ObjectStore::Transaction t;
3109 t.create_collection(cid, 0);
3110 r = queue_transaction(store, ch, std::move(t));
3111 ASSERT_EQ(r, 0);
3112 }
3113 {
3114 ObjectStore::Transaction t;
3115 ghobject_t hoid(hobject_t(sobject_t("obj", CEPH_NOSNAP),
3116 "", UINT32_C(0xffffffff), -1, "nspace"));
3117 t.touch(cid, hoid);
3118 r = queue_transaction(store, ch, std::move(t));
3119 ASSERT_EQ(r, 0);
3120 }
3121 {
3122 vector<ghobject_t> objects;
3123 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
3124 &objects, nullptr, true);
3125 ASSERT_EQ(r, 0);
3126 ASSERT_EQ(objects.size(), 1);
3127 }
3128 }
3129
3130 TEST_P(StoreTest, List_0xfffffff_Hash_Test_in_PG) {
3131 int r = 0;
3132 const int64_t poolid = 1;
3133 coll_t cid(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
3134 auto ch = store->create_new_collection(cid);
3135 {
3136 ObjectStore::Transaction t;
3137 t.create_collection(cid, 0);
3138 r = queue_transaction(store, ch, std::move(t));
3139 ASSERT_EQ(r, 0);
3140 }
3141 {
3142 ObjectStore::Transaction t;
3143 ghobject_t hoid(hobject_t(sobject_t("obj", CEPH_NOSNAP),
3144 "", UINT32_C(0xffffffff), poolid, "nspace"));
3145 t.touch(cid, hoid);
3146 r = queue_transaction(store, ch, std::move(t));
3147 ASSERT_EQ(r, 0);
3148 }
3149 {
3150 vector<ghobject_t> objects;
3151 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
3152 &objects, nullptr, true);
3153 ASSERT_EQ(r, 0);
3154 ASSERT_EQ(objects.size(), 1);
3155 }
3156 }
3157
3158 TEST_P(StoreTest, Sort) {
3159 {
3160 hobject_t a(sobject_t("a", CEPH_NOSNAP));
3161 hobject_t b = a;
3162 ASSERT_EQ(a, b);
3163 b.oid.name = "b";
3164 ASSERT_NE(a, b);
3165 ASSERT_TRUE(a < b);
3166 a.pool = 1;
3167 b.pool = 2;
3168 ASSERT_TRUE(a < b);
3169 a.pool = 3;
3170 ASSERT_TRUE(a > b);
3171 }
3172 {
3173 ghobject_t a(hobject_t(sobject_t("a", CEPH_NOSNAP)));
3174 ghobject_t b(hobject_t(sobject_t("b", CEPH_NOSNAP)));
3175 a.hobj.pool = 1;
3176 b.hobj.pool = 1;
3177 ASSERT_TRUE(a < b);
3178 a.hobj.pool = -3;
3179 ASSERT_TRUE(a < b);
3180 a.hobj.pool = 1;
3181 b.hobj.pool = -3;
3182 ASSERT_TRUE(a > b);
3183 }
3184 }
3185
3186 TEST_P(StoreTest, MultipoolListTest) {
3187 int r;
3188 int poolid = 4373;
3189 coll_t cid = coll_t(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
3190 auto ch = store->create_new_collection(cid);
3191 {
3192 ObjectStore::Transaction t;
3193 t.create_collection(cid, 0);
3194 cerr << "Creating collection " << cid << std::endl;
3195 r = queue_transaction(store, ch, std::move(t));
3196 ASSERT_EQ(r, 0);
3197 }
3198 set<ghobject_t> all, saw;
3199 {
3200 ObjectStore::Transaction t;
3201 for (int i=0; i<200; ++i) {
3202 string name("object_");
3203 name += stringify(i);
3204 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)));
3205 if (rand() & 1)
3206 hoid.hobj.pool = -2 - poolid;
3207 else
3208 hoid.hobj.pool = poolid;
3209 all.insert(hoid);
3210 t.touch(cid, hoid);
3211 cerr << "Creating object " << hoid << std::endl;
3212 }
3213 r = queue_transaction(store, ch, std::move(t));
3214 ASSERT_EQ(r, 0);
3215 }
3216 {
3217 vector<ghobject_t> objects;
3218 ghobject_t next, current;
3219 while (!next.is_max()) {
3220 int r = collection_list(store, ch, current, ghobject_t::get_max(), 50,
3221 &objects, &next);
3222 ASSERT_EQ(r, 0);
3223 cout << " got " << objects.size() << " next " << next << std::endl;
3224 for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
3225 ++p) {
3226 saw.insert(*p);
3227 }
3228 objects.clear();
3229 current = next;
3230 }
3231 ASSERT_EQ(saw, all);
3232 }
3233 {
3234 ObjectStore::Transaction t;
3235 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
3236 t.remove(cid, *p);
3237 t.remove_collection(cid);
3238 cerr << "Cleaning" << std::endl;
3239 r = queue_transaction(store, ch, std::move(t));
3240 ASSERT_EQ(r, 0);
3241 }
3242 }
3243
3244 TEST_P(StoreTest, SimpleCloneTest) {
3245 int r;
3246 coll_t cid;
3247
3248 SetDeathTestStyle("threadsafe");
3249
3250 auto ch = store->create_new_collection(cid);
3251 {
3252 ObjectStore::Transaction t;
3253 t.create_collection(cid, 0);
3254 cerr << "Creating collection " << cid << std::endl;
3255 r = queue_transaction(store, ch, std::move(t));
3256 ASSERT_EQ(r, 0);
3257 }
3258 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
3259 "key", 123, -1, ""));
3260 bufferlist small, large, xlarge, newdata, attr;
3261 small.append("small");
3262 large.append("large");
3263 xlarge.append("xlarge");
3264 {
3265 ObjectStore::Transaction t;
3266 t.touch(cid, hoid);
3267 t.setattr(cid, hoid, "attr1", small);
3268 t.setattr(cid, hoid, "attr2", large);
3269 t.setattr(cid, hoid, "attr3", xlarge);
3270 t.write(cid, hoid, 0, small.length(), small);
3271 t.write(cid, hoid, 10, small.length(), small);
3272 cerr << "Creating object and set attr " << hoid << std::endl;
3273 r = queue_transaction(store, ch, std::move(t));
3274 ASSERT_EQ(r, 0);
3275 }
3276
3277 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
3278 "key", 123, -1, ""));
3279 ghobject_t hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP)));
3280 {
3281 ObjectStore::Transaction t;
3282 t.clone(cid, hoid, hoid2);
3283 t.setattr(cid, hoid2, "attr2", small);
3284 t.rmattr(cid, hoid2, "attr1");
3285 t.write(cid, hoid, 10, large.length(), large);
3286 t.setattr(cid, hoid, "attr1", large);
3287 t.setattr(cid, hoid, "attr2", small);
3288 cerr << "Clone object and rm attr" << std::endl;
3289 r = queue_transaction(store, ch, std::move(t));
3290 ASSERT_EQ(r, 0);
3291
3292 r = store->read(ch, hoid, 10, 5, newdata);
3293 ASSERT_EQ(r, 5);
3294 ASSERT_TRUE(bl_eq(large, newdata));
3295
3296 newdata.clear();
3297 r = store->read(ch, hoid, 0, 5, newdata);
3298 ASSERT_EQ(r, 5);
3299 ASSERT_TRUE(bl_eq(small, newdata));
3300
3301 newdata.clear();
3302 r = store->read(ch, hoid2, 10, 5, newdata);
3303 ASSERT_EQ(r, 5);
3304 ASSERT_TRUE(bl_eq(small, newdata));
3305
3306 r = store->getattr(ch, hoid2, "attr2", attr);
3307 ASSERT_EQ(r, 0);
3308 ASSERT_TRUE(bl_eq(small, attr));
3309
3310 attr.clear();
3311 r = store->getattr(ch, hoid2, "attr3", attr);
3312 ASSERT_EQ(r, 0);
3313 ASSERT_TRUE(bl_eq(xlarge, attr));
3314
3315 attr.clear();
3316 r = store->getattr(ch, hoid, "attr1", attr);
3317 ASSERT_EQ(r, 0);
3318 ASSERT_TRUE(bl_eq(large, attr));
3319 }
3320 {
3321 ObjectStore::Transaction t;
3322 t.remove(cid, hoid);
3323 t.remove(cid, hoid2);
3324 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3325 }
3326 {
3327 bufferlist final;
3328 bufferptr p(16384);
3329 memset(p.c_str(), 1, p.length());
3330 bufferlist pl;
3331 pl.append(p);
3332 final.append(p);
3333 ObjectStore::Transaction t;
3334 t.write(cid, hoid, 0, pl.length(), pl);
3335 t.clone(cid, hoid, hoid2);
3336 bufferptr a(4096);
3337 memset(a.c_str(), 2, a.length());
3338 bufferlist al;
3339 al.append(a);
3340 final.append(a);
3341 t.write(cid, hoid, pl.length(), a.length(), al);
3342 r = queue_transaction(store, ch, std::move(t));
3343 ASSERT_EQ(r, 0);
3344 bufferlist rl;
3345 ASSERT_EQ((int)final.length(),
3346 store->read(ch, hoid, 0, final.length(), rl));
3347 ASSERT_TRUE(bl_eq(rl, final));
3348 }
3349 {
3350 ObjectStore::Transaction t;
3351 t.remove(cid, hoid);
3352 t.remove(cid, hoid2);
3353 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3354 }
3355 {
3356 bufferlist final;
3357 bufferptr p(16384);
3358 memset(p.c_str(), 111, p.length());
3359 bufferlist pl;
3360 pl.append(p);
3361 final.append(p);
3362 ObjectStore::Transaction t;
3363 t.write(cid, hoid, 0, pl.length(), pl);
3364 t.clone(cid, hoid, hoid2);
3365 bufferptr z(4096);
3366 z.zero();
3367 final.append(z);
3368 bufferptr a(4096);
3369 memset(a.c_str(), 112, a.length());
3370 bufferlist al;
3371 al.append(a);
3372 final.append(a);
3373 t.write(cid, hoid, pl.length() + z.length(), a.length(), al);
3374 r = queue_transaction(store, ch, std::move(t));
3375 ASSERT_EQ(r, 0);
3376 bufferlist rl;
3377 ASSERT_EQ((int)final.length(),
3378 store->read(ch, hoid, 0, final.length(), rl));
3379 ASSERT_TRUE(bl_eq(rl, final));
3380 }
3381 {
3382 ObjectStore::Transaction t;
3383 t.remove(cid, hoid);
3384 t.remove(cid, hoid2);
3385 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3386 }
3387 {
3388 bufferlist final;
3389 bufferptr p(16000);
3390 memset(p.c_str(), 5, p.length());
3391 bufferlist pl;
3392 pl.append(p);
3393 final.append(p);
3394 ObjectStore::Transaction t;
3395 t.write(cid, hoid, 0, pl.length(), pl);
3396 t.clone(cid, hoid, hoid2);
3397 bufferptr z(1000);
3398 z.zero();
3399 final.append(z);
3400 bufferptr a(8000);
3401 memset(a.c_str(), 6, a.length());
3402 bufferlist al;
3403 al.append(a);
3404 final.append(a);
3405 t.write(cid, hoid, 17000, a.length(), al);
3406 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3407 bufferlist rl;
3408 ASSERT_EQ((int)final.length(),
3409 store->read(ch, hoid, 0, final.length(), rl));
3410 /*cout << "expected:\n";
3411 final.hexdump(cout);
3412 cout << "got:\n";
3413 rl.hexdump(cout);*/
3414 ASSERT_TRUE(bl_eq(rl, final));
3415 }
3416 {
3417 ObjectStore::Transaction t;
3418 t.remove(cid, hoid);
3419 t.remove(cid, hoid2);
3420 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3421 }
3422 {
3423 bufferptr p(1048576);
3424 memset(p.c_str(), 3, p.length());
3425 bufferlist pl;
3426 pl.append(p);
3427 ObjectStore::Transaction t;
3428 t.write(cid, hoid, 0, pl.length(), pl);
3429 t.clone(cid, hoid, hoid2);
3430 bufferptr a(65536);
3431 memset(a.c_str(), 4, a.length());
3432 bufferlist al;
3433 al.append(a);
3434 t.write(cid, hoid, a.length(), a.length(), al);
3435 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3436 bufferlist rl;
3437 bufferlist final;
3438 final.substr_of(pl, 0, al.length());
3439 final.append(al);
3440 bufferlist end;
3441 end.substr_of(pl, al.length()*2, pl.length() - al.length()*2);
3442 final.append(end);
3443 ASSERT_EQ((int)final.length(),
3444 store->read(ch, hoid, 0, final.length(), rl));
3445 /*cout << "expected:\n";
3446 final.hexdump(cout);
3447 cout << "got:\n";
3448 rl.hexdump(cout);*/
3449 ASSERT_TRUE(bl_eq(rl, final));
3450 }
3451 {
3452 ObjectStore::Transaction t;
3453 t.remove(cid, hoid);
3454 t.remove(cid, hoid2);
3455 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3456 }
3457 {
3458 bufferptr p(65536);
3459 memset(p.c_str(), 7, p.length());
3460 bufferlist pl;
3461 pl.append(p);
3462 ObjectStore::Transaction t;
3463 t.write(cid, hoid, 0, pl.length(), pl);
3464 t.clone(cid, hoid, hoid2);
3465 bufferptr a(4096);
3466 memset(a.c_str(), 8, a.length());
3467 bufferlist al;
3468 al.append(a);
3469 t.write(cid, hoid, 32768, a.length(), al);
3470 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3471 bufferlist rl;
3472 bufferlist final;
3473 final.substr_of(pl, 0, 32768);
3474 final.append(al);
3475 bufferlist end;
3476 end.substr_of(pl, final.length(), pl.length() - final.length());
3477 final.append(end);
3478 ASSERT_EQ((int)final.length(),
3479 store->read(ch, hoid, 0, final.length(), rl));
3480 /*cout << "expected:\n";
3481 final.hexdump(cout);
3482 cout << "got:\n";
3483 rl.hexdump(cout);*/
3484 ASSERT_TRUE(bl_eq(rl, final));
3485 }
3486 {
3487 ObjectStore::Transaction t;
3488 t.remove(cid, hoid);
3489 t.remove(cid, hoid2);
3490 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3491 }
3492 {
3493 bufferptr p(65536);
3494 memset(p.c_str(), 9, p.length());
3495 bufferlist pl;
3496 pl.append(p);
3497 ObjectStore::Transaction t;
3498 t.write(cid, hoid, 0, pl.length(), pl);
3499 t.clone(cid, hoid, hoid2);
3500 bufferptr a(4096);
3501 memset(a.c_str(), 10, a.length());
3502 bufferlist al;
3503 al.append(a);
3504 t.write(cid, hoid, 33768, a.length(), al);
3505 ASSERT_EQ(0, queue_transaction(store, ch, std::move(t)));
3506 bufferlist rl;
3507 bufferlist final;
3508 final.substr_of(pl, 0, 33768);
3509 final.append(al);
3510 bufferlist end;
3511 end.substr_of(pl, final.length(), pl.length() - final.length());
3512 final.append(end);
3513 ASSERT_EQ((int)final.length(),
3514 store->read(ch, hoid, 0, final.length(), rl));
3515 /*cout << "expected:\n";
3516 final.hexdump(cout);
3517 cout << "got:\n";
3518 rl.hexdump(cout);*/
3519 ASSERT_TRUE(bl_eq(rl, final));
3520 }
3521
3522 {
3523 //verify if non-empty collection is properly handled after store reload
3524 ch.reset();
3525 r = store->umount();
3526 ASSERT_EQ(r, 0);
3527 r = store->mount();
3528 ASSERT_EQ(r, 0);
3529 ch = store->open_collection(cid);
3530
3531 ObjectStore::Transaction t;
3532 t.remove_collection(cid);
3533 cerr << "Invalid rm coll" << std::endl;
3534 PrCtl unset_dumpable;
3535 EXPECT_DEATH(queue_transaction(store, ch, std::move(t)), "");
3536 }
3537 {
3538 ObjectStore::Transaction t;
3539 t.touch(cid, hoid3); //new record in db
3540 r = queue_transaction(store, ch, std::move(t));
3541 ASSERT_EQ(r, 0);
3542 }
3543 {
3544 ObjectStore::Transaction t;
3545 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
3546 cerr << "Invalid rm coll again" << std::endl;
3547 ch.reset();
3548 r = store->umount();
3549 ASSERT_EQ(r, 0);
3550 r = store->mount();
3551 ASSERT_EQ(r, 0);
3552 ch = store->open_collection(cid);
3553
3554 t.remove(cid, hoid);
3555 t.remove(cid, hoid2);
3556 t.remove_collection(cid);
3557 PrCtl unset_dumpable;
3558 EXPECT_DEATH(queue_transaction(store, ch, std::move(t)), "");
3559 }
3560 {
3561 ObjectStore::Transaction t;
3562 t.remove(cid, hoid);
3563 t.remove(cid, hoid2);
3564 t.remove(cid, hoid3);
3565 t.remove_collection(cid);
3566 cerr << "Cleaning" << std::endl;
3567 r = queue_transaction(store, ch, std::move(t));
3568 ASSERT_EQ(r, 0);
3569 }
3570 }
3571
3572 TEST_P(StoreTest, OmapSimple) {
3573 int r;
3574 coll_t cid;
3575 auto ch = store->create_new_collection(cid);
3576 {
3577 ObjectStore::Transaction t;
3578 t.create_collection(cid, 0);
3579 cerr << "Creating collection " << cid << std::endl;
3580 r = queue_transaction(store, ch, std::move(t));
3581 ASSERT_EQ(r, 0);
3582 }
3583 ghobject_t hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP),
3584 "key", 123, -1, ""));
3585 bufferlist small;
3586 small.append("small");
3587 map<string,bufferlist> km;
3588 km["foo"] = small;
3589 km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3590 bufferlist header;
3591 header.append("this is a header");
3592 {
3593 ObjectStore::Transaction t;
3594 t.touch(cid, hoid);
3595 t.omap_setkeys(cid, hoid, km);
3596 t.omap_setheader(cid, hoid, header);
3597 cerr << "Creating object and set omap " << hoid << std::endl;
3598 r = queue_transaction(store, ch, std::move(t));
3599 ASSERT_EQ(r, 0);
3600 }
3601 // get header, keys
3602 {
3603 bufferlist h;
3604 map<string,bufferlist> r;
3605 store->omap_get(ch, hoid, &h, &r);
3606 ASSERT_TRUE(bl_eq(header, h));
3607 ASSERT_EQ(r.size(), km.size());
3608 cout << "r: " << r << std::endl;
3609 }
3610 // test iterator with seek_to_first
3611 {
3612 map<string,bufferlist> r;
3613 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(ch, hoid);
3614 for (iter->seek_to_first(); iter->valid(); iter->next()) {
3615 r[iter->key()] = iter->value();
3616 }
3617 cout << "r: " << r << std::endl;
3618 ASSERT_EQ(r.size(), km.size());
3619 }
3620 // test iterator with initial lower_bound
3621 {
3622 map<string,bufferlist> r;
3623 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(ch, hoid);
3624 for (iter->lower_bound(string()); iter->valid(); iter->next()) {
3625 r[iter->key()] = iter->value();
3626 }
3627 cout << "r: " << r << std::endl;
3628 ASSERT_EQ(r.size(), km.size());
3629 }
3630 {
3631 ObjectStore::Transaction t;
3632 t.remove(cid, hoid);
3633 t.remove_collection(cid);
3634 cerr << "Cleaning" << std::endl;
3635 r = queue_transaction(store, ch, std::move(t));
3636 ASSERT_EQ(r, 0);
3637 }
3638 }
3639
3640 TEST_P(StoreTest, OmapCloneTest) {
3641 int r;
3642 coll_t cid;
3643 auto ch = store->create_new_collection(cid);
3644 {
3645 ObjectStore::Transaction t;
3646 t.create_collection(cid, 0);
3647 cerr << "Creating collection " << cid << std::endl;
3648 r = queue_transaction(store, ch, std::move(t));
3649 ASSERT_EQ(r, 0);
3650 }
3651 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
3652 "key", 123, -1, ""));
3653 bufferlist small;
3654 small.append("small");
3655 map<string,bufferlist> km;
3656 km["foo"] = small;
3657 km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3658 bufferlist header;
3659 header.append("this is a header");
3660 {
3661 ObjectStore::Transaction t;
3662 t.touch(cid, hoid);
3663 t.omap_setkeys(cid, hoid, km);
3664 t.omap_setheader(cid, hoid, header);
3665 cerr << "Creating object and set omap " << hoid << std::endl;
3666 r = queue_transaction(store, ch, std::move(t));
3667 ASSERT_EQ(r, 0);
3668 }
3669 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
3670 "key", 123, -1, ""));
3671 {
3672 ObjectStore::Transaction t;
3673 t.clone(cid, hoid, hoid2);
3674 cerr << "Clone object" << std::endl;
3675 r = queue_transaction(store, ch, std::move(t));
3676 ASSERT_EQ(r, 0);
3677 }
3678 {
3679 map<string,bufferlist> r;
3680 bufferlist h;
3681 store->omap_get(ch, hoid2, &h, &r);
3682 ASSERT_TRUE(bl_eq(header, h));
3683 ASSERT_EQ(r.size(), km.size());
3684 }
3685 {
3686 ObjectStore::Transaction t;
3687 t.remove(cid, hoid);
3688 t.remove(cid, hoid2);
3689 t.remove_collection(cid);
3690 cerr << "Cleaning" << std::endl;
3691 r = queue_transaction(store, ch, std::move(t));
3692 ASSERT_EQ(r, 0);
3693 }
3694 }
3695
3696 TEST_P(StoreTest, SimpleCloneRangeTest) {
3697 int r;
3698 coll_t cid;
3699 auto ch = store->create_new_collection(cid);
3700 {
3701 ObjectStore::Transaction t;
3702 t.create_collection(cid, 0);
3703 cerr << "Creating collection " << cid << std::endl;
3704 r = queue_transaction(store, ch, std::move(t));
3705 ASSERT_EQ(r, 0);
3706 }
3707 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3708 hoid.hobj.pool = -1;
3709 bufferlist small, newdata;
3710 small.append("small");
3711 {
3712 ObjectStore::Transaction t;
3713 t.write(cid, hoid, 10, 5, small);
3714 cerr << "Creating object and write bl " << hoid << std::endl;
3715 r = queue_transaction(store, ch, std::move(t));
3716 ASSERT_EQ(r, 0);
3717 }
3718 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
3719 hoid2.hobj.pool = -1;
3720 {
3721 ObjectStore::Transaction t;
3722 t.clone_range(cid, hoid, hoid2, 10, 5, 10);
3723 cerr << "Clone range object" << std::endl;
3724 r = queue_transaction(store, ch, std::move(t));
3725 ASSERT_EQ(r, 0);
3726 r = store->read(ch, hoid2, 10, 5, newdata);
3727 ASSERT_EQ(r, 5);
3728 ASSERT_TRUE(bl_eq(small, newdata));
3729 }
3730 {
3731 ObjectStore::Transaction t;
3732 t.truncate(cid, hoid, 1024*1024);
3733 t.clone_range(cid, hoid, hoid2, 0, 1024*1024, 0);
3734 cerr << "Clone range object" << std::endl;
3735 r = queue_transaction(store, ch, std::move(t));
3736 ASSERT_EQ(r, 0);
3737 struct stat stat, stat2;
3738 r = store->stat(ch, hoid, &stat);
3739 r = store->stat(ch, hoid2, &stat2);
3740 ASSERT_EQ(stat.st_size, stat2.st_size);
3741 ASSERT_EQ(1024*1024, stat2.st_size);
3742 }
3743 {
3744 ObjectStore::Transaction t;
3745 t.remove(cid, hoid);
3746 t.remove(cid, hoid2);
3747 r = queue_transaction(store, ch, std::move(t));
3748 ASSERT_EQ(r, 0);
3749 }
3750 }
3751
3752 #if defined(WITH_BLUESTORE)
3753 TEST_P(StoreTest, BlueStoreUnshareBlobTest) {
3754 if (string(GetParam()) != "bluestore")
3755 return;
3756 if (smr) {
3757 cout << "SKIP: non-deterministic behavior with smr" << std::endl;
3758 return;
3759 }
3760 int r;
3761 coll_t cid;
3762 auto ch = store->create_new_collection(cid);
3763 {
3764 ObjectStore::Transaction t;
3765 t.create_collection(cid, 0);
3766 cerr << "Creating collection " << cid << std::endl;
3767 r = queue_transaction(store, ch, std::move(t));
3768 ASSERT_EQ(r, 0);
3769 }
3770 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3771 hoid.hobj.pool = -1;
3772 ghobject_t hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3773 hoid2.hobj.pool = -1;
3774 hoid2.generation = 2;
3775 {
3776 // check if blob is unshared properly
3777 bufferlist data, newdata;
3778 data.append(string(8192, 'a'));
3779
3780 ObjectStore::Transaction t;
3781 t.write(cid, hoid, 0, data.length(), data);
3782 cerr << "Creating object and write 8K " << hoid << std::endl;
3783 r = queue_transaction(store, ch, std::move(t));
3784 ASSERT_EQ(r, 0);
3785
3786 ObjectStore::Transaction t2;
3787 t2.clone_range(cid, hoid, hoid2, 0, 4096, 0);
3788 cerr << "Clone range object" << std::endl;
3789 r = queue_transaction(store, ch, std::move(t2));
3790 ASSERT_EQ(r, 0);
3791
3792 data.clear();
3793 data.append(string(4096, 'b'));
3794
3795 ObjectStore::Transaction t3;
3796 t3.write(cid, hoid, 0, data.length(), data);
3797 cerr << "Writing 4k to source object " << hoid << std::endl;
3798 r = queue_transaction(store, ch, std::move(t3));
3799 ASSERT_EQ(r, 0);
3800
3801 {
3802 // this trims hoid one out of onode cache
3803 EXPECT_EQ(store->umount(), 0);
3804 EXPECT_EQ(store->mount(), 0);
3805 ch = store->open_collection(cid);
3806 }
3807
3808 ObjectStore::Transaction t4;
3809 t4.remove(cid, hoid2);
3810 cerr << "Deleting dest object" << hoid2 << std::endl;
3811 r = queue_transaction(store, ch, std::move(t4));
3812 ASSERT_EQ(r, 0);
3813
3814 {
3815 // this ensures remove operation submitted to kv store
3816 EXPECT_EQ(store->umount(), 0);
3817 EXPECT_EQ(store->mount(), 0);
3818 ch = store->open_collection(cid);
3819 }
3820
3821 bufferlist resdata;
3822 r = store->read(ch, hoid, 0, 0x2000, resdata);
3823 ASSERT_EQ(r, 0x2000);
3824
3825 {
3826 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
3827 auto* kv = bstore->get_kv();
3828
3829 // to be inline with BlueStore.cc
3830 const string PREFIX_SHARED_BLOB = "X";
3831
3832 size_t cnt = 0;
3833 auto it = kv->get_iterator(PREFIX_SHARED_BLOB);
3834 ceph_assert(it);
3835 for (it->lower_bound(string()); it->valid(); it->next()) {
3836 ++cnt;
3837 }
3838 ASSERT_EQ(cnt, 0);
3839 }
3840 }
3841 {
3842 ObjectStore::Transaction t;
3843 t.remove(cid, hoid);
3844 t.remove_collection(cid);
3845 cerr << "Cleaning" << std::endl;
3846 r = queue_transaction(store, ch, std::move(t));
3847 ASSERT_EQ(r, 0);
3848 }
3849 }
3850
3851 TEST_P(StoreTest, BlueStoreUnshareBlobBugTest) {
3852 if (string(GetParam()) != "bluestore")
3853 return;
3854 int r;
3855 coll_t cid;
3856 auto ch = store->create_new_collection(cid);
3857 {
3858 ObjectStore::Transaction t;
3859 t.create_collection(cid, 0);
3860 cerr << "Creating collection " << cid << std::endl;
3861 r = queue_transaction(store, ch, std::move(t));
3862 ASSERT_EQ(r, 0);
3863 }
3864 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3865 hoid.hobj.pool = -1;
3866 ghobject_t hoid2(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3867 hoid2.hobj.pool = -1;
3868 hoid2.generation = 2;
3869 {
3870 // check if blob is unshared properly
3871 bufferlist data, newdata;
3872 data.append(string(8192, 'a'));
3873
3874 ObjectStore::Transaction t;
3875 t.write(cid, hoid, 0, data.length(), data);
3876 cerr << "Creating object and write 8K " << hoid << std::endl;
3877 r = queue_transaction(store, ch, std::move(t));
3878 ASSERT_EQ(r, 0);
3879
3880 ObjectStore::Transaction t2;
3881 t2.clone_range(cid, hoid, hoid2, 0, 4096, 0);
3882 cerr << "Clone range object" << std::endl;
3883 r = queue_transaction(store, ch, std::move(t2));
3884 ASSERT_EQ(r, 0);
3885
3886 data.clear();
3887 data.append(string(4096, 'b'));
3888
3889 ObjectStore::Transaction t3;
3890 t3.write(cid, hoid, 0, data.length(), data);
3891 cerr << "Writing 4k to source object " << hoid << std::endl;
3892 r = queue_transaction(store, ch, std::move(t3));
3893 ASSERT_EQ(r, 0);
3894
3895 {
3896 // this trims hoid one out of onode cache
3897 EXPECT_EQ(store->umount(), 0);
3898 EXPECT_EQ(store->mount(), 0);
3899 ch = store->open_collection(cid);
3900 }
3901
3902 ObjectStore::Transaction t4;
3903 t4.write(cid, hoid2, 0, data.length(), data);
3904 cerr << "Writing 4k to second object " << hoid2 << std::endl;
3905 r = queue_transaction(store, ch, std::move(t4));
3906 ASSERT_EQ(r, 0);
3907
3908 bufferlist resdata;
3909 r = store->read(ch, hoid, 0, 0x2000, resdata);
3910 ASSERT_EQ(r, 0x2000);
3911
3912 {
3913 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
3914 auto* kv = bstore->get_kv();
3915
3916 // to be inline with BlueStore.cc
3917 const string PREFIX_SHARED_BLOB = "X";
3918
3919 size_t cnt = 0;
3920 auto it = kv->get_iterator(PREFIX_SHARED_BLOB);
3921 ceph_assert(it);
3922 for (it->lower_bound(string()); it->valid(); it->next()) {
3923 ++cnt;
3924 }
3925 // This shows a bug in unsharing a blob,
3926 // after writing to 0x0~1000 to hoid2 share blob at hoid should be
3927 //unshared but it doesn't in the current implementation
3928 ASSERT_EQ(cnt, 1);
3929 }
3930 }
3931 {
3932 ObjectStore::Transaction t;
3933 t.remove(cid, hoid);
3934 t.remove(cid, hoid2);
3935 t.remove_collection(cid);
3936 cerr << "Cleaning" << std::endl;
3937 r = queue_transaction(store, ch, std::move(t));
3938 ASSERT_EQ(r, 0);
3939 }
3940 }
3941 #endif
3942
3943 TEST_P(StoreTest, SimpleObjectLongnameTest) {
3944 int r;
3945 coll_t cid;
3946 auto ch = store->create_new_collection(cid);
3947 {
3948 ObjectStore::Transaction t;
3949 t.create_collection(cid, 0);
3950 cerr << "Creating collection " << cid << std::endl;
3951 r = queue_transaction(store, ch, std::move(t));
3952 ASSERT_EQ(r, 0);
3953 }
3954 ghobject_t hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP)));
3955 {
3956 ObjectStore::Transaction t;
3957 t.touch(cid, hoid);
3958 cerr << "Creating object " << hoid << std::endl;
3959 r = queue_transaction(store, ch, std::move(t));
3960 ASSERT_EQ(r, 0);
3961 }
3962 {
3963 ObjectStore::Transaction t;
3964 t.remove(cid, hoid);
3965 t.remove_collection(cid);
3966 cerr << "Cleaning" << std::endl;
3967 r = queue_transaction(store, ch, std::move(t));
3968 ASSERT_EQ(r, 0);
3969 }
3970 }
3971
3972 ghobject_t generate_long_name(unsigned i)
3973 {
3974 stringstream name;
3975 name << "object id " << i << " ";
3976 for (unsigned j = 0; j < 500; ++j) name << 'a';
3977 ghobject_t hoid(hobject_t(sobject_t(name.str(), CEPH_NOSNAP)));
3978 hoid.hobj.set_hash(i % 2);
3979 return hoid;
3980 }
3981
3982 TEST_P(StoreTest, LongnameSplitTest) {
3983 int r;
3984 coll_t cid;
3985 auto ch = store->create_new_collection(cid);
3986 {
3987 ObjectStore::Transaction t;
3988 t.create_collection(cid, 0);
3989 cerr << "Creating collection " << cid << std::endl;
3990 r = queue_transaction(store, ch, std::move(t));
3991 ASSERT_EQ(0, r);
3992 }
3993 for (unsigned i = 0; i < 320; ++i) {
3994 ObjectStore::Transaction t;
3995 ghobject_t hoid = generate_long_name(i);
3996 t.touch(cid, hoid);
3997 cerr << "Creating object " << hoid << std::endl;
3998 r = queue_transaction(store, ch, std::move(t));
3999 ASSERT_EQ(0, r);
4000 }
4001
4002 ghobject_t test_obj = generate_long_name(319);
4003 ghobject_t test_obj_2 = test_obj;
4004 test_obj_2.generation = 0;
4005 {
4006 ObjectStore::Transaction t;
4007 // should cause a split
4008 t.collection_move_rename(
4009 cid, test_obj,
4010 cid, test_obj_2);
4011 r = queue_transaction(store, ch, std::move(t));
4012 ASSERT_EQ(0, r);
4013 }
4014
4015 for (unsigned i = 0; i < 319; ++i) {
4016 ObjectStore::Transaction t;
4017 ghobject_t hoid = generate_long_name(i);
4018 t.remove(cid, hoid);
4019 cerr << "Removing object " << hoid << std::endl;
4020 r = queue_transaction(store, ch, std::move(t));
4021 ASSERT_EQ(0, r);
4022 }
4023 {
4024 ObjectStore::Transaction t;
4025 t.remove(cid, test_obj_2);
4026 t.remove_collection(cid);
4027 cerr << "Cleaning" << std::endl;
4028 r = queue_transaction(store, ch, std::move(t));
4029 ASSERT_EQ(0, r);
4030 }
4031
4032 }
4033
4034 TEST_P(StoreTest, ManyObjectTest) {
4035 int NUM_OBJS = 2000;
4036 int r = 0;
4037 coll_t cid;
4038 string base = "";
4039 for (int i = 0; i < 100; ++i) base.append("aaaaa");
4040 set<ghobject_t> created;
4041 auto ch = store->create_new_collection(cid);
4042 {
4043 ObjectStore::Transaction t;
4044 t.create_collection(cid, 0);
4045 r = queue_transaction(store, ch, std::move(t));
4046 ASSERT_EQ(r, 0);
4047 }
4048 for (int i = 0; i < NUM_OBJS; ++i) {
4049 if (!(i % 5)) {
4050 cerr << "Object " << i << std::endl;
4051 }
4052 ObjectStore::Transaction t;
4053 char buf[100];
4054 snprintf(buf, sizeof(buf), "%d", i);
4055 ghobject_t hoid(hobject_t(sobject_t(string(buf) + base, CEPH_NOSNAP)));
4056 t.touch(cid, hoid);
4057 created.insert(hoid);
4058 r = queue_transaction(store, ch, std::move(t));
4059 ASSERT_EQ(r, 0);
4060 }
4061
4062 for (set<ghobject_t>::iterator i = created.begin();
4063 i != created.end();
4064 ++i) {
4065 struct stat buf;
4066 ASSERT_TRUE(!store->stat(ch, *i, &buf));
4067 }
4068
4069 set<ghobject_t> listed, listed2;
4070 vector<ghobject_t> objects;
4071 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
4072 &objects, 0);
4073 ASSERT_EQ(r, 0);
4074
4075 cerr << "objects.size() is " << objects.size() << std::endl;
4076 for (vector<ghobject_t> ::iterator i = objects.begin();
4077 i != objects.end();
4078 ++i) {
4079 listed.insert(*i);
4080 ASSERT_TRUE(created.count(*i));
4081 }
4082 ASSERT_TRUE(listed.size() == created.size());
4083
4084 ghobject_t start, next;
4085 objects.clear();
4086 r = collection_list(
4087 store,
4088 ch,
4089 ghobject_t::get_max(),
4090 ghobject_t::get_max(),
4091 50,
4092 &objects,
4093 &next
4094 );
4095 ASSERT_EQ(r, 0);
4096 ASSERT_TRUE(objects.empty());
4097
4098 objects.clear();
4099 listed.clear();
4100 ghobject_t start2, next2;
4101 while (1) {
4102 r = collection_list(store, ch, start, ghobject_t::get_max(), 50, &objects,
4103 &next);
4104 ASSERT_TRUE(sorted(objects));
4105 ASSERT_EQ(r, 0);
4106 listed.insert(objects.begin(), objects.end());
4107 if (objects.size() < 50) {
4108 ASSERT_TRUE(next.is_max());
4109 break;
4110 }
4111 objects.clear();
4112
4113 start = next;
4114 }
4115 cerr << "listed.size() is " << listed.size() << std::endl;
4116 ASSERT_TRUE(listed.size() == created.size());
4117 if (listed2.size()) {
4118 ASSERT_EQ(listed.size(), listed2.size());
4119 }
4120 for (set<ghobject_t>::iterator i = listed.begin();
4121 i != listed.end();
4122 ++i) {
4123 ASSERT_TRUE(created.count(*i));
4124 }
4125
4126 for (set<ghobject_t>::iterator i = created.begin();
4127 i != created.end();
4128 ++i) {
4129 ObjectStore::Transaction t;
4130 t.remove(cid, *i);
4131 r = queue_transaction(store, ch, std::move(t));
4132 ASSERT_EQ(r, 0);
4133 }
4134 cerr << "cleaning up" << std::endl;
4135 {
4136 ObjectStore::Transaction t;
4137 t.remove_collection(cid);
4138 r = queue_transaction(store, ch, std::move(t));
4139 ASSERT_EQ(r, 0);
4140 }
4141 }
4142
4143
4144 class ObjectGenerator {
4145 public:
4146 virtual ghobject_t create_object(gen_type *gen) = 0;
4147 virtual ~ObjectGenerator() {}
4148 };
4149
4150 class MixedGenerator : public ObjectGenerator {
4151 public:
4152 unsigned seq;
4153 int64_t poolid;
4154 explicit MixedGenerator(int64_t p) : seq(0), poolid(p) {}
4155 ghobject_t create_object(gen_type *gen) override {
4156 char buf[100];
4157 snprintf(buf, sizeof(buf), "OBJ_%u", seq);
4158 string name(buf);
4159 if (seq % 2) {
4160 for (unsigned i = 0; i < 300; ++i) {
4161 name.push_back('a');
4162 }
4163 }
4164 ++seq;
4165 return ghobject_t(
4166 hobject_t(
4167 name, string(), rand() & 2 ? CEPH_NOSNAP : rand(),
4168 (((seq / 1024) % 2) * 0xF00 ) +
4169 (seq & 0xFF),
4170 poolid, ""));
4171 }
4172 };
4173
4174 class SyntheticWorkloadState {
4175 struct Object {
4176 bufferlist data;
4177 map<string, bufferlist> attrs;
4178 };
4179 public:
4180 static const unsigned max_in_flight = 16;
4181 static const unsigned max_objects = 3000;
4182 static const unsigned max_attr_size = 5;
4183 static const unsigned max_attr_name_len = 100;
4184 static const unsigned max_attr_value_len = 1024 * 64;
4185 coll_t cid;
4186 unsigned write_alignment;
4187 unsigned max_object_len, max_write_len;
4188 unsigned in_flight;
4189 map<ghobject_t, Object> contents;
4190 set<ghobject_t> available_objects;
4191 set<ghobject_t>::iterator next_available_object;
4192 set<ghobject_t> in_flight_objects;
4193 ObjectGenerator *object_gen;
4194 gen_type *rng;
4195 ObjectStore *store;
4196 ObjectStore::CollectionHandle ch;
4197
4198 ceph::mutex lock = ceph::make_mutex("State lock");
4199 ceph::condition_variable cond;
4200
4201 struct EnterExit {
4202 const char *msg;
4203 explicit EnterExit(const char *m) : msg(m) {
4204 //cout << pthread_self() << " enter " << msg << std::endl;
4205 }
4206 ~EnterExit() {
4207 //cout << pthread_self() << " exit " << msg << std::endl;
4208 }
4209 };
4210
4211 class C_SyntheticOnReadable : public Context {
4212 public:
4213 SyntheticWorkloadState *state;
4214 ghobject_t hoid;
4215 C_SyntheticOnReadable(SyntheticWorkloadState *state, ghobject_t hoid)
4216 : state(state), hoid(hoid) {}
4217
4218 void finish(int r) override {
4219 std::lock_guard locker{state->lock};
4220 EnterExit ee("onreadable finish");
4221 ASSERT_TRUE(state->in_flight_objects.count(hoid));
4222 ASSERT_EQ(r, 0);
4223 state->in_flight_objects.erase(hoid);
4224 if (state->contents.count(hoid))
4225 state->available_objects.insert(hoid);
4226 --(state->in_flight);
4227 state->cond.notify_all();
4228
4229 bufferlist r2;
4230 r = state->store->read(state->ch, hoid, 0, state->contents[hoid].data.length(), r2);
4231 ceph_assert(bl_eq(state->contents[hoid].data, r2));
4232 state->cond.notify_all();
4233 }
4234 };
4235
4236 class C_SyntheticOnStash : public Context {
4237 public:
4238 SyntheticWorkloadState *state;
4239 ghobject_t oid, noid;
4240
4241 C_SyntheticOnStash(SyntheticWorkloadState *state,
4242 ghobject_t oid, ghobject_t noid)
4243 : state(state), oid(oid), noid(noid) {}
4244
4245 void finish(int r) override {
4246 std::lock_guard locker{state->lock};
4247 EnterExit ee("stash finish");
4248 ASSERT_TRUE(state->in_flight_objects.count(oid));
4249 ASSERT_EQ(r, 0);
4250 state->in_flight_objects.erase(oid);
4251 if (state->contents.count(noid))
4252 state->available_objects.insert(noid);
4253 --(state->in_flight);
4254 bufferlist r2;
4255 r = state->store->read(
4256 state->ch, noid, 0,
4257 state->contents[noid].data.length(), r2);
4258 ceph_assert(bl_eq(state->contents[noid].data, r2));
4259 state->cond.notify_all();
4260 }
4261 };
4262
4263 class C_SyntheticOnClone : public Context {
4264 public:
4265 SyntheticWorkloadState *state;
4266 ghobject_t oid, noid;
4267
4268 C_SyntheticOnClone(SyntheticWorkloadState *state,
4269 ghobject_t oid, ghobject_t noid)
4270 : state(state), oid(oid), noid(noid) {}
4271
4272 void finish(int r) override {
4273 std::lock_guard locker{state->lock};
4274 EnterExit ee("clone finish");
4275 ASSERT_TRUE(state->in_flight_objects.count(oid));
4276 ASSERT_EQ(r, 0);
4277 state->in_flight_objects.erase(oid);
4278 if (state->contents.count(oid))
4279 state->available_objects.insert(oid);
4280 if (state->contents.count(noid))
4281 state->available_objects.insert(noid);
4282 --(state->in_flight);
4283 bufferlist r2;
4284 r = state->store->read(state->ch, noid, 0, state->contents[noid].data.length(), r2);
4285 ceph_assert(bl_eq(state->contents[noid].data, r2));
4286 state->cond.notify_all();
4287 }
4288 };
4289
4290 static void filled_byte_array(bufferlist& bl, size_t size)
4291 {
4292 static const char alphanum[] = "0123456789"
4293 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4294 "abcdefghijklmnopqrstuvwxyz";
4295 if (!size) {
4296 return;
4297 }
4298 bufferptr bp(size);
4299 for (unsigned int i = 0; i < size - 1; i++) {
4300 // severely limit entropy so we can compress...
4301 bp[i] = alphanum[rand() % 10]; //(sizeof(alphanum) - 1)];
4302 }
4303 bp[size - 1] = '\0';
4304
4305 bl.append(bp);
4306 }
4307
4308 SyntheticWorkloadState(ObjectStore *store,
4309 ObjectGenerator *gen,
4310 gen_type *rng,
4311 coll_t cid,
4312 unsigned max_size,
4313 unsigned max_write,
4314 unsigned alignment)
4315 : cid(cid), write_alignment(alignment), max_object_len(max_size),
4316 max_write_len(max_write), in_flight(0),
4317 next_available_object(available_objects.end()),
4318 object_gen(gen), rng(rng), store(store) {}
4319
4320 int init() {
4321 ObjectStore::Transaction t;
4322 ch = store->create_new_collection(cid);
4323 t.create_collection(cid, 0);
4324 return queue_transaction(store, ch, std::move(t));
4325 }
4326 void shutdown() {
4327 ghobject_t next;
4328 while (1) {
4329 vector<ghobject_t> objects;
4330 int r = collection_list(store, ch, next, ghobject_t::get_max(), 10,
4331 &objects, &next);
4332 ceph_assert(r >= 0);
4333 if (objects.size() == 0)
4334 break;
4335 ObjectStore::Transaction t;
4336 std::map<std::string, ceph::buffer::list> attrset;
4337 for (vector<ghobject_t>::iterator p = objects.begin();
4338 p != objects.end(); ++p) {
4339 t.remove(cid, *p);
4340 }
4341 queue_transaction(store, ch, std::move(t));
4342 }
4343 ObjectStore::Transaction t;
4344 t.remove_collection(cid);
4345 queue_transaction(store, ch, std::move(t));
4346 }
4347 void statfs(store_statfs_t& stat) {
4348 store->statfs(&stat);
4349 }
4350
4351 ghobject_t get_uniform_random_object(std::unique_lock<ceph::mutex>& locker) {
4352 cond.wait(locker, [this] {
4353 return in_flight < max_in_flight && !available_objects.empty();
4354 });
4355 boost::uniform_int<> choose(0, available_objects.size() - 1);
4356 int index = choose(*rng);
4357 set<ghobject_t>::iterator i = available_objects.begin();
4358 for ( ; index > 0; --index, ++i) ;
4359 ghobject_t ret = *i;
4360 return ret;
4361 }
4362
4363 ghobject_t get_next_object(std::unique_lock<ceph::mutex>& locker) {
4364 cond.wait(locker, [this] {
4365 return in_flight < max_in_flight && !available_objects.empty();
4366 });
4367
4368 if (next_available_object == available_objects.end()) {
4369 next_available_object = available_objects.begin();
4370 }
4371
4372 ghobject_t ret = *next_available_object;
4373 ++next_available_object;
4374 return ret;
4375 }
4376
4377 void wait_for_ready(std::unique_lock<ceph::mutex>& locker) {
4378 cond.wait(locker, [this] { return in_flight < max_in_flight; });
4379 }
4380
4381 void wait_for_done() {
4382 std::unique_lock locker{lock};
4383 cond.wait(locker, [this] { return in_flight == 0; });
4384 }
4385
4386 bool can_create() {
4387 return (available_objects.size() + in_flight_objects.size()) < max_objects;
4388 }
4389
4390 bool can_unlink() {
4391 return (available_objects.size() + in_flight_objects.size()) > 0;
4392 }
4393
4394 unsigned get_random_alloc_hints() {
4395 unsigned f = 0;
4396 {
4397 boost::uniform_int<> u(0, 3);
4398 switch (u(*rng)) {
4399 case 1:
4400 f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE;
4401 break;
4402 case 2:
4403 f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE;
4404 break;
4405 }
4406 }
4407 {
4408 boost::uniform_int<> u(0, 3);
4409 switch (u(*rng)) {
4410 case 1:
4411 f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ;
4412 break;
4413 case 2:
4414 f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ;
4415 break;
4416 }
4417 }
4418 {
4419 // append_only, immutable
4420 boost::uniform_int<> u(0, 4);
4421 f |= u(*rng) << 4;
4422 }
4423 {
4424 boost::uniform_int<> u(0, 3);
4425 switch (u(*rng)) {
4426 case 1:
4427 f |= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED;
4428 break;
4429 case 2:
4430 f |= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED;
4431 break;
4432 }
4433 }
4434 {
4435 boost::uniform_int<> u(0, 3);
4436 switch (u(*rng)) {
4437 case 1:
4438 f |= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
4439 break;
4440 case 2:
4441 f |= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
4442 break;
4443 }
4444 }
4445 return f;
4446 }
4447
4448 int touch() {
4449 std::unique_lock locker{lock};
4450 EnterExit ee("touch");
4451 if (!can_create())
4452 return -ENOSPC;
4453 wait_for_ready(locker);
4454 ghobject_t new_obj = object_gen->create_object(rng);
4455 available_objects.erase(new_obj);
4456 ObjectStore::Transaction t;
4457 t.touch(cid, new_obj);
4458 boost::uniform_int<> u(17, 22);
4459 boost::uniform_int<> v(12, 17);
4460 t.set_alloc_hint(cid, new_obj,
4461 1ull << u(*rng),
4462 1ull << v(*rng),
4463 get_random_alloc_hints());
4464 ++in_flight;
4465 in_flight_objects.insert(new_obj);
4466 if (!contents.count(new_obj))
4467 contents[new_obj] = Object();
4468 t.register_on_applied(new C_SyntheticOnReadable(this, new_obj));
4469 int status = store->queue_transaction(ch, std::move(t));
4470 return status;
4471 }
4472
4473 int stash() {
4474 std::unique_lock locker{lock};
4475 EnterExit ee("stash");
4476 if (!can_unlink())
4477 return -ENOENT;
4478 if (!can_create())
4479 return -ENOSPC;
4480 wait_for_ready(locker);
4481
4482 ghobject_t old_obj;
4483 int max = 20;
4484 do {
4485 old_obj = get_uniform_random_object(locker);
4486 } while (--max && !contents[old_obj].data.length());
4487 available_objects.erase(old_obj);
4488 ghobject_t new_obj = old_obj;
4489 new_obj.generation++;
4490 available_objects.erase(new_obj);
4491
4492 ObjectStore::Transaction t;
4493 t.collection_move_rename(cid, old_obj, cid, new_obj);
4494 ++in_flight;
4495 in_flight_objects.insert(old_obj);
4496
4497 contents[new_obj].attrs = contents[old_obj].attrs;
4498 contents[new_obj].data = contents[old_obj].data;
4499 contents.erase(old_obj);
4500 t.register_on_applied(new C_SyntheticOnStash(this, old_obj, new_obj));
4501 int status = store->queue_transaction(ch, std::move(t));
4502 return status;
4503 }
4504
4505 int clone() {
4506 std::unique_lock locker{lock};
4507 EnterExit ee("clone");
4508 if (!can_unlink())
4509 return -ENOENT;
4510 if (!can_create())
4511 return -ENOSPC;
4512 wait_for_ready(locker);
4513
4514 ghobject_t old_obj;
4515 int max = 20;
4516 do {
4517 old_obj = get_uniform_random_object(locker);
4518 } while (--max && !contents[old_obj].data.length());
4519 available_objects.erase(old_obj);
4520 ghobject_t new_obj = object_gen->create_object(rng);
4521 // make the hash match
4522 new_obj.hobj.set_hash(old_obj.hobj.get_hash());
4523 available_objects.erase(new_obj);
4524
4525 ObjectStore::Transaction t;
4526 t.clone(cid, old_obj, new_obj);
4527 ++in_flight;
4528 in_flight_objects.insert(old_obj);
4529
4530 contents[new_obj].attrs = contents[old_obj].attrs;
4531 contents[new_obj].data = contents[old_obj].data;
4532
4533 t.register_on_applied(new C_SyntheticOnClone(this, old_obj, new_obj));
4534 int status = store->queue_transaction(ch, std::move(t));
4535 return status;
4536 }
4537
4538 int clone_range() {
4539 std::unique_lock locker{lock};
4540 EnterExit ee("clone_range");
4541 if (!can_unlink())
4542 return -ENOENT;
4543 if (!can_create())
4544 return -ENOSPC;
4545 wait_for_ready(locker);
4546
4547 ghobject_t old_obj;
4548 int max = 20;
4549 do {
4550 old_obj = get_uniform_random_object(locker);
4551 } while (--max && !contents[old_obj].data.length());
4552 bufferlist &srcdata = contents[old_obj].data;
4553 if (srcdata.length() == 0) {
4554 return 0;
4555 }
4556 available_objects.erase(old_obj);
4557 ghobject_t new_obj = get_uniform_random_object(locker);
4558 available_objects.erase(new_obj);
4559
4560 boost::uniform_int<> u1(0, max_object_len - max_write_len);
4561 boost::uniform_int<> u2(0, max_write_len);
4562 uint64_t srcoff = u1(*rng);
4563 // make src and dst offsets match, since that's what the osd does
4564 uint64_t dstoff = srcoff; //u1(*rng);
4565 uint64_t len = u2(*rng);
4566 if (write_alignment) {
4567 srcoff = round_up_to(srcoff, write_alignment);
4568 dstoff = round_up_to(dstoff, write_alignment);
4569 len = round_up_to(len, write_alignment);
4570 }
4571
4572 if (srcoff > srcdata.length() - 1) {
4573 srcoff = srcdata.length() - 1;
4574 }
4575 if (srcoff + len > srcdata.length()) {
4576 len = srcdata.length() - srcoff;
4577 }
4578 if (0)
4579 cout << __func__ << " from " << srcoff << "~" << len
4580 << " (size " << srcdata.length() << ") to "
4581 << dstoff << "~" << len << std::endl;
4582
4583 ObjectStore::Transaction t;
4584 t.clone_range(cid, old_obj, new_obj, srcoff, len, dstoff);
4585 ++in_flight;
4586 in_flight_objects.insert(old_obj);
4587
4588 bufferlist bl;
4589 if (srcoff < srcdata.length()) {
4590 if (srcoff + len > srcdata.length()) {
4591 bl.substr_of(srcdata, srcoff, srcdata.length() - srcoff);
4592 } else {
4593 bl.substr_of(srcdata, srcoff, len);
4594 }
4595 }
4596
4597 bufferlist& dstdata = contents[new_obj].data;
4598 if (dstdata.length() <= dstoff) {
4599 if (bl.length() > 0) {
4600 dstdata.append_zero(dstoff - dstdata.length());
4601 dstdata.append(bl);
4602 }
4603 } else {
4604 bufferlist value;
4605 ceph_assert(dstdata.length() > dstoff);
4606 dstdata.cbegin().copy(dstoff, value);
4607 value.append(bl);
4608 if (value.length() < dstdata.length())
4609 dstdata.cbegin(value.length()).copy(
4610 dstdata.length() - value.length(), value);
4611 value.swap(dstdata);
4612 }
4613
4614 t.register_on_applied(new C_SyntheticOnClone(this, old_obj, new_obj));
4615 int status = store->queue_transaction(ch, std::move(t));
4616 return status;
4617 }
4618
4619
4620 int write() {
4621 std::unique_lock locker{lock};
4622 EnterExit ee("write");
4623 if (!can_unlink())
4624 return -ENOENT;
4625 wait_for_ready(locker);
4626
4627 ghobject_t new_obj = get_uniform_random_object(locker);
4628 available_objects.erase(new_obj);
4629 ObjectStore::Transaction t;
4630
4631 boost::uniform_int<> u1(0, max_object_len - max_write_len);
4632 boost::uniform_int<> u2(0, max_write_len);
4633 uint64_t offset = u1(*rng);
4634 uint64_t len = u2(*rng);
4635 bufferlist bl;
4636 if (write_alignment) {
4637 offset = round_up_to(offset, write_alignment);
4638 len = round_up_to(len, write_alignment);
4639 }
4640
4641 filled_byte_array(bl, len);
4642
4643 bufferlist& data = contents[new_obj].data;
4644 if (data.length() <= offset) {
4645 if (len > 0) {
4646 data.append_zero(offset-data.length());
4647 data.append(bl);
4648 }
4649 } else {
4650 bufferlist value;
4651 ceph_assert(data.length() > offset);
4652 data.cbegin().copy(offset, value);
4653 value.append(bl);
4654 if (value.length() < data.length())
4655 data.cbegin(value.length()).copy(
4656 data.length()-value.length(), value);
4657 value.swap(data);
4658 }
4659
4660 t.write(cid, new_obj, offset, len, bl);
4661 ++in_flight;
4662 in_flight_objects.insert(new_obj);
4663 t.register_on_applied(new C_SyntheticOnReadable(this, new_obj));
4664 int status = store->queue_transaction(ch, std::move(t));
4665 return status;
4666 }
4667
4668 int truncate() {
4669 std::unique_lock locker{lock};
4670 EnterExit ee("truncate");
4671 if (!can_unlink())
4672 return -ENOENT;
4673 wait_for_ready(locker);
4674
4675 ghobject_t obj = get_uniform_random_object(locker);
4676 available_objects.erase(obj);
4677 ObjectStore::Transaction t;
4678
4679 boost::uniform_int<> choose(0, max_object_len);
4680 size_t len = choose(*rng);
4681 if (write_alignment) {
4682 len = round_up_to(len, write_alignment);
4683 }
4684
4685 t.truncate(cid, obj, len);
4686 ++in_flight;
4687 in_flight_objects.insert(obj);
4688 bufferlist& data = contents[obj].data;
4689 if (data.length() <= len) {
4690 data.append_zero(len - data.length());
4691 } else {
4692 bufferlist bl;
4693 data.cbegin().copy(len, bl);
4694 bl.swap(data);
4695 }
4696
4697 t.register_on_applied(new C_SyntheticOnReadable(this, obj));
4698 int status = store->queue_transaction(ch, std::move(t));
4699 return status;
4700 }
4701
4702 int zero() {
4703 std::unique_lock locker{lock};
4704 EnterExit ee("zero");
4705 if (!can_unlink())
4706 return -ENOENT;
4707 wait_for_ready(locker);
4708
4709 ghobject_t new_obj = get_uniform_random_object(locker);
4710 available_objects.erase(new_obj);
4711 ObjectStore::Transaction t;
4712
4713 boost::uniform_int<> u1(0, max_object_len - max_write_len);
4714 boost::uniform_int<> u2(0, max_write_len);
4715 uint64_t offset = u1(*rng);
4716 uint64_t len = u2(*rng);
4717 if (write_alignment) {
4718 offset = round_up_to(offset, write_alignment);
4719 len = round_up_to(len, write_alignment);
4720 }
4721
4722 if (len > 0) {
4723 auto& data = contents[new_obj].data;
4724 if (data.length() < offset + len) {
4725 data.append_zero(offset+len-data.length());
4726 }
4727 bufferlist n;
4728 n.substr_of(data, 0, offset);
4729 n.append_zero(len);
4730 if (data.length() > offset + len)
4731 data.cbegin(offset + len).copy(data.length() - offset - len, n);
4732 data.swap(n);
4733 }
4734
4735 t.zero(cid, new_obj, offset, len);
4736 ++in_flight;
4737 in_flight_objects.insert(new_obj);
4738 t.register_on_applied(new C_SyntheticOnReadable(this, new_obj));
4739 int status = store->queue_transaction(ch, std::move(t));
4740 return status;
4741 }
4742
4743 void read() {
4744 EnterExit ee("read");
4745 boost::uniform_int<> u1(0, max_object_len/2);
4746 boost::uniform_int<> u2(0, max_object_len);
4747 uint64_t offset = u1(*rng);
4748 uint64_t len = u2(*rng);
4749 if (offset > len)
4750 swap(offset, len);
4751
4752 ghobject_t obj;
4753 bufferlist expected;
4754 int r;
4755 {
4756 std::unique_lock locker{lock};
4757 EnterExit ee("read locked");
4758 if (!can_unlink())
4759 return ;
4760 wait_for_ready(locker);
4761
4762 obj = get_uniform_random_object(locker);
4763 expected = contents[obj].data;
4764 }
4765 bufferlist bl, result;
4766 if (0) cout << " obj " << obj
4767 << " size " << expected.length()
4768 << " offset " << offset
4769 << " len " << len << std::endl;
4770 r = store->read(ch, obj, offset, len, result);
4771 if (offset >= expected.length()) {
4772 ASSERT_EQ(r, 0);
4773 } else {
4774 size_t max_len = expected.length() - offset;
4775 if (len > max_len)
4776 len = max_len;
4777 ceph_assert(len == result.length());
4778 ASSERT_EQ(len, result.length());
4779 expected.cbegin(offset).copy(len, bl);
4780 ASSERT_EQ(r, (int)len);
4781 ASSERT_TRUE(bl_eq(bl, result));
4782 }
4783 }
4784
4785 int setattrs() {
4786 std::unique_lock locker{lock};
4787 EnterExit ee("setattrs");
4788 if (!can_unlink())
4789 return -ENOENT;
4790 wait_for_ready(locker);
4791
4792 ghobject_t obj = get_uniform_random_object(locker);
4793 available_objects.erase(obj);
4794 ObjectStore::Transaction t;
4795
4796 boost::uniform_int<> u0(1, max_attr_size);
4797 boost::uniform_int<> u1(4, max_attr_name_len);
4798 boost::uniform_int<> u2(4, max_attr_value_len);
4799 boost::uniform_int<> u3(0, 100);
4800 uint64_t size = u0(*rng);
4801 uint64_t name_len;
4802 map<string, bufferlist, less<>> attrs;
4803 set<string> keys;
4804 for (map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
4805 it != contents[obj].attrs.end(); ++it)
4806 keys.insert(it->first);
4807
4808 while (size--) {
4809 bufferlist name, value;
4810 uint64_t get_exist = u3(*rng);
4811 uint64_t value_len = u2(*rng);
4812 filled_byte_array(value, value_len);
4813 if (get_exist < 50 && keys.size()) {
4814 set<string>::iterator k = keys.begin();
4815 attrs[*k] = value;
4816 contents[obj].attrs[*k] = value;
4817 keys.erase(k);
4818 } else {
4819 name_len = u1(*rng);
4820 filled_byte_array(name, name_len);
4821 attrs[name.c_str()] = value;
4822 contents[obj].attrs[name.c_str()] = value;
4823 }
4824 }
4825 t.setattrs(cid, obj, attrs);
4826 ++in_flight;
4827 in_flight_objects.insert(obj);
4828 t.register_on_applied(new C_SyntheticOnReadable(this, obj));
4829 int status = store->queue_transaction(ch, std::move(t));
4830 return status;
4831 }
4832
4833 int set_fixed_attrs(size_t entries, size_t key_size, size_t val_size) {
4834 std::unique_lock locker{ lock };
4835 EnterExit ee("setattrs");
4836 if (!can_unlink())
4837 return -ENOENT;
4838 wait_for_ready(locker);
4839
4840 ghobject_t obj = get_next_object(locker);
4841 available_objects.erase(obj);
4842 ObjectStore::Transaction t;
4843
4844 map<string, bufferlist, less<>> attrs;
4845 set<string> keys;
4846
4847 while (entries--) {
4848 bufferlist name, value;
4849 filled_byte_array(value, val_size);
4850 filled_byte_array(name, key_size);
4851 attrs[name.c_str()] = value;
4852 contents[obj].attrs[name.c_str()] = value;
4853 }
4854 t.setattrs(cid, obj, attrs);
4855 ++in_flight;
4856 in_flight_objects.insert(obj);
4857 t.register_on_applied(new C_SyntheticOnReadable(this, obj));
4858 int status = store->queue_transaction(ch, std::move(t));
4859 return status;
4860 }
4861
4862 void getattrs() {
4863 EnterExit ee("getattrs");
4864 ghobject_t obj;
4865 map<string, bufferlist> expected;
4866 {
4867 std::unique_lock locker{lock};
4868 EnterExit ee("getattrs locked");
4869 if (!can_unlink())
4870 return ;
4871 wait_for_ready(locker);
4872
4873 int retry = 10;
4874 do {
4875 obj = get_uniform_random_object(locker);
4876 if (!--retry)
4877 return ;
4878 } while (contents[obj].attrs.empty());
4879 expected = contents[obj].attrs;
4880 }
4881 map<string, bufferlist, less<>> attrs;
4882 int r = store->getattrs(ch, obj, attrs);
4883 ASSERT_TRUE(r == 0);
4884 ASSERT_TRUE(attrs.size() == expected.size());
4885 for (map<string, bufferlist>::iterator it = expected.begin();
4886 it != expected.end(); ++it) {
4887 ASSERT_TRUE(bl_eq(attrs[it->first], it->second));
4888 }
4889 }
4890
4891 void getattr() {
4892 EnterExit ee("getattr");
4893 ghobject_t obj;
4894 int r;
4895 int retry;
4896 map<string, bufferlist> expected;
4897 {
4898 std::unique_lock locker{lock};
4899 EnterExit ee("getattr locked");
4900 if (!can_unlink())
4901 return ;
4902 wait_for_ready(locker);
4903
4904 retry = 10;
4905 do {
4906 obj = get_uniform_random_object(locker);
4907 if (!--retry)
4908 return ;
4909 } while (contents[obj].attrs.empty());
4910 expected = contents[obj].attrs;
4911 }
4912 boost::uniform_int<> u(0, expected.size()-1);
4913 retry = u(*rng);
4914 map<string, bufferlist>::iterator it = expected.begin();
4915 while (retry) {
4916 retry--;
4917 ++it;
4918 }
4919
4920 bufferlist bl;
4921 r = store->getattr(ch, obj, it->first, bl);
4922 ASSERT_EQ(r, 0);
4923 ASSERT_TRUE(bl_eq(it->second, bl));
4924 }
4925
4926 int rmattr() {
4927 std::unique_lock locker{lock};
4928 EnterExit ee("rmattr");
4929 if (!can_unlink())
4930 return -ENOENT;
4931 wait_for_ready(locker);
4932
4933 ghobject_t obj;
4934 int retry = 10;
4935 do {
4936 obj = get_uniform_random_object(locker);
4937 if (!--retry)
4938 return 0;
4939 } while (contents[obj].attrs.empty());
4940
4941 boost::uniform_int<> u(0, contents[obj].attrs.size()-1);
4942 retry = u(*rng);
4943 map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
4944 while (retry) {
4945 retry--;
4946 ++it;
4947 }
4948
4949 available_objects.erase(obj);
4950 ObjectStore::Transaction t;
4951 t.rmattr(cid, obj, it->first);
4952
4953 contents[obj].attrs.erase(it->first);
4954 ++in_flight;
4955 in_flight_objects.insert(obj);
4956 t.register_on_applied(new C_SyntheticOnReadable(this, obj));
4957 int status = store->queue_transaction(ch, std::move(t));
4958 return status;
4959 }
4960
4961 void fsck(bool deep) {
4962 std::unique_lock locker{lock};
4963 EnterExit ee("fsck");
4964 cond.wait(locker, [this] { return in_flight == 0; });
4965 ch.reset();
4966 store->umount();
4967 int r = store->fsck(deep);
4968 ceph_assert(r == 0 || r == -EOPNOTSUPP);
4969 store->mount();
4970 ch = store->open_collection(cid);
4971 }
4972
4973 void scan() {
4974 std::unique_lock locker{lock};
4975 EnterExit ee("scan");
4976 cond.wait(locker, [this] { return in_flight == 0; });
4977 vector<ghobject_t> objects;
4978 set<ghobject_t> objects_set, objects_set2;
4979 ghobject_t next, current;
4980 while (1) {
4981 //cerr << "scanning..." << std::endl;
4982 int r = collection_list(store, ch, current, ghobject_t::get_max(), 100,
4983 &objects, &next);
4984 ASSERT_EQ(r, 0);
4985 ASSERT_TRUE(sorted(objects));
4986 objects_set.insert(objects.begin(), objects.end());
4987 objects.clear();
4988 if (next.is_max()) break;
4989 current = next;
4990 }
4991 if (objects_set.size() != available_objects.size()) {
4992 for (set<ghobject_t>::iterator p = objects_set.begin();
4993 p != objects_set.end();
4994 ++p)
4995 if (available_objects.count(*p) == 0) {
4996 cerr << "+ " << *p << std::endl;
4997 ceph_abort();
4998 }
4999 for (set<ghobject_t>::iterator p = available_objects.begin();
5000 p != available_objects.end();
5001 ++p)
5002 if (objects_set.count(*p) == 0)
5003 cerr << "- " << *p << std::endl;
5004 //cerr << " objects_set: " << objects_set << std::endl;
5005 //cerr << " available_set: " << available_objects << std::endl;
5006 ceph_abort_msg("badness");
5007 }
5008
5009 ASSERT_EQ(objects_set.size(), available_objects.size());
5010 for (set<ghobject_t>::iterator i = objects_set.begin();
5011 i != objects_set.end();
5012 ++i) {
5013 ASSERT_GT(available_objects.count(*i), (unsigned)0);
5014 }
5015
5016 int r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(),
5017 INT_MAX, &objects, 0);
5018 ASSERT_EQ(r, 0);
5019 objects_set2.insert(objects.begin(), objects.end());
5020 ASSERT_EQ(objects_set2.size(), available_objects.size());
5021 for (set<ghobject_t>::iterator i = objects_set2.begin();
5022 i != objects_set2.end();
5023 ++i) {
5024 ASSERT_GT(available_objects.count(*i), (unsigned)0);
5025 if (available_objects.count(*i) == 0) {
5026 cerr << "+ " << *i << std::endl;
5027 }
5028 }
5029 }
5030
5031 void stat() {
5032 EnterExit ee("stat");
5033 ghobject_t hoid;
5034 uint64_t expected;
5035 {
5036 std::unique_lock locker{lock};
5037 EnterExit ee("stat lock1");
5038 if (!can_unlink())
5039 return ;
5040 hoid = get_uniform_random_object(locker);
5041 in_flight_objects.insert(hoid);
5042 available_objects.erase(hoid);
5043 ++in_flight;
5044 expected = contents[hoid].data.length();
5045 }
5046 struct stat buf;
5047 int r = store->stat(ch, hoid, &buf);
5048 ASSERT_EQ(0, r);
5049 ceph_assert((uint64_t)buf.st_size == expected);
5050 ASSERT_TRUE((uint64_t)buf.st_size == expected);
5051 {
5052 std::lock_guard locker{lock};
5053 EnterExit ee("stat lock2");
5054 --in_flight;
5055 cond.notify_all();
5056 in_flight_objects.erase(hoid);
5057 available_objects.insert(hoid);
5058 }
5059 }
5060
5061 int unlink() {
5062 std::unique_lock locker{lock};
5063 EnterExit ee("unlink");
5064 if (!can_unlink())
5065 return -ENOENT;
5066 ghobject_t to_remove = get_uniform_random_object(locker);
5067 ObjectStore::Transaction t;
5068 t.remove(cid, to_remove);
5069 ++in_flight;
5070 available_objects.erase(to_remove);
5071 in_flight_objects.insert(to_remove);
5072 contents.erase(to_remove);
5073 t.register_on_applied(new C_SyntheticOnReadable(this, to_remove));
5074 int status = store->queue_transaction(ch, std::move(t));
5075 return status;
5076 }
5077
5078 void print_internal_state() {
5079 std::lock_guard locker{lock};
5080 cerr << "available_objects: " << available_objects.size()
5081 << " in_flight_objects: " << in_flight_objects.size()
5082 << " total objects: " << in_flight_objects.size() + available_objects.size()
5083 << " in_flight " << in_flight << std::endl;
5084 }
5085 };
5086
5087
5088 void StoreTest::doSyntheticTest(
5089 int num_ops,
5090 uint64_t max_obj, uint64_t max_wr, uint64_t align)
5091 {
5092 MixedGenerator gen(555);
5093 gen_type rng(time(NULL));
5094 coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
5095
5096 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
5097 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
5098 g_ceph_context->_conf.apply_changes(nullptr);
5099
5100 SyntheticWorkloadState test_obj(store.get(), &gen, &rng, cid,
5101 max_obj, max_wr, align);
5102 test_obj.init();
5103 for (int i = 0; i < num_ops/10; ++i) {
5104 if (!(i % 500)) cerr << "seeding object " << i << std::endl;
5105 test_obj.touch();
5106 }
5107 for (int i = 0; i < num_ops; ++i) {
5108 if (!(i % 1000)) {
5109 cerr << "Op " << i << std::endl;
5110 test_obj.print_internal_state();
5111 }
5112 boost::uniform_int<> true_false(0, 999);
5113 int val = true_false(rng);
5114 if (val > 998) {
5115 test_obj.fsck(true);
5116 } else if (val > 997) {
5117 test_obj.fsck(false);
5118 } else if (val > 970) {
5119 test_obj.scan();
5120 } else if (val > 950) {
5121 test_obj.stat();
5122 } else if (val > 850) {
5123 test_obj.zero();
5124 } else if (val > 800) {
5125 test_obj.unlink();
5126 } else if (val > 550) {
5127 test_obj.write();
5128 } else if (val > 500) {
5129 test_obj.clone();
5130 } else if (val > 450) {
5131 test_obj.clone_range();
5132 } else if (val > 300) {
5133 test_obj.stash();
5134 } else if (val > 100) {
5135 test_obj.read();
5136 } else {
5137 test_obj.truncate();
5138 }
5139 }
5140 test_obj.wait_for_done();
5141 test_obj.shutdown();
5142 }
5143
5144 TEST_P(StoreTest, Synthetic) {
5145 doSyntheticTest(10000, 400*1024, 40*1024, 0);
5146 }
5147
5148 #if defined(WITH_BLUESTORE)
5149 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixSharding) {
5150 if (string(GetParam()) != "bluestore")
5151 return;
5152
5153 const char *m[][10] = {
5154 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
5155 { "num_ops", "50000", 0 },
5156 { "max_write", "65536", 0 },
5157 { "max_size", "262144", 0 },
5158 { "alignment", "4096", 0 },
5159 { "bluestore_max_blob_size", "65536", 0 },
5160 { "bluestore_extent_map_shard_min_size", "60", 0 },
5161 { "bluestore_extent_map_shard_max_size", "300", 0 },
5162 { "bluestore_extent_map_shard_target_size", "150", 0 },
5163 { "bluestore_default_buffered_read", "true", 0 },
5164 { "bluestore_default_buffered_write", "true", 0 },
5165 { 0 },
5166 };
5167 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
5168 }
5169
5170 TEST_P(StoreTestSpecificAUSize, ZipperPatternSharded) {
5171 if(string(GetParam()) != "bluestore")
5172 return;
5173 StartDeferred(4096);
5174
5175 int r;
5176 coll_t cid;
5177 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
5178 auto ch = store->create_new_collection(cid);
5179 {
5180 ObjectStore::Transaction t;
5181 t.create_collection(cid, 0);
5182 cerr << "Creating collection " << cid << std::endl;
5183 r = queue_transaction(store, ch, std::move(t));
5184 ASSERT_EQ(r, 0);
5185 }
5186 bufferlist bl;
5187 int len = 4096;
5188 bufferptr bp(len);
5189 bp.zero();
5190 bl.append(bp);
5191 for (int i=0; i<1000; ++i) {
5192 ObjectStore::Transaction t;
5193 t.write(cid, a, i*2*len, len, bl, 0);
5194 r = queue_transaction(store, ch, std::move(t));
5195 ASSERT_EQ(r, 0);
5196 }
5197 for (int i=0; i<1000; ++i) {
5198 ObjectStore::Transaction t;
5199 t.write(cid, a, i*2*len + 1, len, bl, 0);
5200 r = queue_transaction(store, ch, std::move(t));
5201 ASSERT_EQ(r, 0);
5202 }
5203 {
5204 ObjectStore::Transaction t;
5205 t.remove(cid, a);
5206 t.remove_collection(cid);
5207 cerr << "Cleaning" << std::endl;
5208 r = queue_transaction(store, ch, std::move(t));
5209 ASSERT_EQ(r, 0);
5210 }
5211 }
5212
5213 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumAlgorithm) {
5214 if (string(GetParam()) != "bluestore")
5215 return;
5216
5217 const char *m[][10] = {
5218 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
5219 { "max_write", "65536", 0 },
5220 { "max_size", "1048576", 0 },
5221 { "alignment", "16", 0 },
5222 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
5223 "xxhash64", "none", 0 },
5224 { "bluestore_default_buffered_write", "false", 0 },
5225 { 0 },
5226 };
5227 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
5228 }
5229
5230 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumVsCompression) {
5231 if (string(GetParam()) != "bluestore")
5232 return;
5233
5234 const char *m[][10] = {
5235 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
5236 { "max_write", "131072", 0 },
5237 { "max_size", "262144", 0 },
5238 { "alignment", "512", 0 },
5239 { "bluestore_compression_mode", "force", 0},
5240 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
5241 { "bluestore_csum_type", "crc32c", 0 },
5242 { "bluestore_default_buffered_read", "true", "false", 0 },
5243 { "bluestore_default_buffered_write", "true", "false", 0 },
5244 { "bluestore_sync_submit_transaction", "false", 0 },
5245 { 0 },
5246 };
5247 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
5248 }
5249
5250 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompression) {
5251 if (string(GetParam()) != "bluestore")
5252 return;
5253
5254 const char *m[][10] = {
5255 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5256 { "max_write", "1048576", 0 },
5257 { "max_size", "4194304", 0 },
5258 { "alignment", "65536", 0 },
5259 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
5260 { "bluestore_default_buffered_write", "false", 0 },
5261 { "bluestore_sync_submit_transaction", "true", 0 },
5262 { 0 },
5263 };
5264 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
5265 }
5266
5267 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompressionAlgorithm) {
5268 if (string(GetParam()) != "bluestore")
5269 return;
5270
5271 const char *m[][10] = {
5272 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5273 { "max_write", "1048576", 0 },
5274 { "max_size", "4194304", 0 },
5275 { "alignment", "65536", 0 },
5276 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
5277 { "bluestore_compression_mode", "force", 0 },
5278 { "bluestore_default_buffered_write", "false", 0 },
5279 { 0 },
5280 };
5281 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
5282 }
5283
5284 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixNoCsum) {
5285 if (string(GetParam()) != "bluestore")
5286 return;
5287
5288 const char *m[][10] = {
5289 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5290 { "max_write", "65536", 0 },
5291 { "max_size", "1048576", 0 },
5292 { "alignment", "512", 0 },
5293 { "bluestore_max_blob_size", "262144", 0 },
5294 { "bluestore_compression_mode", "force", "none", 0},
5295 { "bluestore_csum_type", "none", 0},
5296 { "bluestore_default_buffered_read", "true", "false", 0 },
5297 { "bluestore_default_buffered_write", "true", 0 },
5298 { "bluestore_sync_submit_transaction", "true", "false", 0 },
5299 { 0 },
5300 };
5301 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
5302 }
5303
5304 TEST_P(StoreTestSpecificAUSize, SyntheticMatrixPreferDeferred) {
5305 if (string(GetParam()) != "bluestore")
5306 return;
5307
5308 const char *m[][10] = {
5309 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
5310 { "max_write", "65536", 0 },
5311 { "max_size", "1048576", 0 },
5312 { "alignment", "512", 0 },
5313 { "bluestore_max_blob_size", "262144", 0 },
5314 { "bluestore_compression_mode", "force", "none", 0},
5315 { "bluestore_prefer_deferred_size", "32768", "0", 0},
5316 { 0 },
5317 };
5318 do_matrix(m, std::bind(&StoreTest::doSyntheticTest, this, _1, _2, _3, _4));
5319 }
5320 #endif // WITH_BLUESTORE
5321
5322 TEST_P(StoreTest, AttrSynthetic) {
5323 MixedGenerator gen(447);
5324 gen_type rng(time(NULL));
5325 coll_t cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD));
5326
5327 SyntheticWorkloadState test_obj(store.get(), &gen, &rng, cid, 40*1024, 4*1024, 0);
5328 test_obj.init();
5329 for (int i = 0; i < 500; ++i) {
5330 if (!(i % 10)) cerr << "seeding object " << i << std::endl;
5331 test_obj.touch();
5332 }
5333 for (int i = 0; i < 1000; ++i) {
5334 if (!(i % 100)) {
5335 cerr << "Op " << i << std::endl;
5336 test_obj.print_internal_state();
5337 }
5338 boost::uniform_int<> true_false(0, 99);
5339 int val = true_false(rng);
5340 if (val > 97) {
5341 test_obj.scan();
5342 } else if (val > 93) {
5343 test_obj.stat();
5344 } else if (val > 75) {
5345 test_obj.rmattr();
5346 } else if (val > 47) {
5347 test_obj.setattrs();
5348 } else if (val > 45) {
5349 test_obj.clone();
5350 } else if (val > 37) {
5351 test_obj.stash();
5352 } else if (val > 30) {
5353 test_obj.getattrs();
5354 } else {
5355 test_obj.getattr();
5356 }
5357 }
5358 test_obj.wait_for_done();
5359 test_obj.shutdown();
5360 }
5361
5362 TEST_P(StoreTest, HashCollisionTest) {
5363 int64_t poolid = 11;
5364 coll_t cid(spg_t(pg_t(0,poolid),shard_id_t::NO_SHARD));
5365 int r;
5366 auto ch = store->create_new_collection(cid);
5367 {
5368 ObjectStore::Transaction t;
5369 t.create_collection(cid, 0);
5370 r = queue_transaction(store, ch, std::move(t));
5371 ASSERT_EQ(r, 0);
5372 }
5373 string base = "";
5374 for (int i = 0; i < 100; ++i) base.append("aaaaa");
5375 set<ghobject_t> created;
5376 for (int n = 0; n < 10; ++n) {
5377 char nbuf[100];
5378 sprintf(nbuf, "n%d", n);
5379 for (int i = 0; i < 1000; ++i) {
5380 char buf[100];
5381 sprintf(buf, "%d", i);
5382 if (!(i % 100)) {
5383 cerr << "Object n" << n << " "<< i << std::endl;
5384 }
5385 ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, 0, poolid, string(nbuf)));
5386 {
5387 ObjectStore::Transaction t;
5388 t.touch(cid, hoid);
5389 r = queue_transaction(store, ch, std::move(t));
5390 ASSERT_EQ(r, 0);
5391 }
5392 created.insert(hoid);
5393 }
5394 }
5395 vector<ghobject_t> objects;
5396 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
5397 &objects, 0);
5398 ASSERT_EQ(r, 0);
5399 set<ghobject_t> listed(objects.begin(), objects.end());
5400 cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
5401 ASSERT_TRUE(listed.size() == created.size());
5402 objects.clear();
5403 listed.clear();
5404 ghobject_t current, next;
5405 while (1) {
5406 r = collection_list(store, ch, current, ghobject_t::get_max(), 60, &objects,
5407 &next);
5408 ASSERT_EQ(r, 0);
5409 ASSERT_TRUE(sorted(objects));
5410 for (vector<ghobject_t>::iterator i = objects.begin();
5411 i != objects.end();
5412 ++i) {
5413 if (listed.count(*i))
5414 cerr << *i << " repeated" << std::endl;
5415 listed.insert(*i);
5416 }
5417 if (objects.size() < 50) {
5418 ASSERT_TRUE(next.is_max());
5419 break;
5420 }
5421 objects.clear();
5422 current = next;
5423 }
5424 cerr << "listed.size() is " << listed.size() << std::endl;
5425 ASSERT_TRUE(listed.size() == created.size());
5426 for (set<ghobject_t>::iterator i = listed.begin();
5427 i != listed.end();
5428 ++i) {
5429 ASSERT_TRUE(created.count(*i));
5430 }
5431
5432 for (set<ghobject_t>::iterator i = created.begin();
5433 i != created.end();
5434 ++i) {
5435 ObjectStore::Transaction t;
5436 t.remove(cid, *i);
5437 r = queue_transaction(store, ch, std::move(t));
5438 ASSERT_EQ(r, 0);
5439 }
5440 ObjectStore::Transaction t;
5441 t.remove_collection(cid);
5442 r = queue_transaction(store, ch, std::move(t));
5443 ASSERT_EQ(r, 0);
5444 }
5445
5446 TEST_P(StoreTest, HashCollisionSorting) {
5447 bool disable_legacy = (string(GetParam()) == "bluestore");
5448
5449 char buf121664318_1[] = {18, -119, -121, -111, 0};
5450 char buf121664318_2[] = {19, 127, -121, 32, 0};
5451 char buf121664318_3[] = {19, -118, 15, 19, 0};
5452 char buf121664318_4[] = {28, 27, -116, -113, 0};
5453 char buf121664318_5[] = {28, 27, -115, -124, 0};
5454
5455 char buf121666222_1[] = {18, -119, -120, -111, 0};
5456 char buf121666222_2[] = {19, 127, -120, 32, 0};
5457 char buf121666222_3[] = {19, -118, 15, 30, 0};
5458 char buf121666222_4[] = {29, 17, -126, -113, 0};
5459 char buf121666222_5[] = {29, 17, -125, -124, 0};
5460
5461 std::map<uint32_t, std::vector<std::string>> object_names = {
5462 {121664318, {{buf121664318_1},
5463 {buf121664318_2},
5464 {buf121664318_3},
5465 {buf121664318_4},
5466 {buf121664318_5}}},
5467 {121666222, {{buf121666222_1},
5468 {buf121666222_2},
5469 {buf121666222_3},
5470 {buf121666222_4},
5471 {buf121666222_5}}}};
5472
5473 int64_t poolid = 111;
5474 coll_t cid = coll_t(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
5475 auto ch = store->create_new_collection(cid);
5476 {
5477 ObjectStore::Transaction t;
5478 t.create_collection(cid, 0);
5479 int r = queue_transaction(store, ch, std::move(t));
5480 ASSERT_EQ(r, 0);
5481 }
5482
5483 std::set<ghobject_t> created;
5484 for (auto &[hash, names] : object_names) {
5485 for (auto &name : names) {
5486 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP),
5487 string(),
5488 hash,
5489 poolid,
5490 string()));
5491 ASSERT_EQ(hash, hoid.hobj.get_hash());
5492 ObjectStore::Transaction t;
5493 t.touch(cid, hoid);
5494 int r = queue_transaction(store, ch, std::move(t));
5495 ASSERT_EQ(r, 0);
5496 created.insert(hoid);
5497 }
5498 }
5499
5500 vector<ghobject_t> objects;
5501 int r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(),
5502 INT_MAX, &objects, 0, disable_legacy);
5503 ASSERT_EQ(r, 0);
5504 ASSERT_EQ(created.size(), objects.size());
5505 auto it = objects.begin();
5506 for (auto &hoid : created) {
5507 ASSERT_EQ(hoid, *it);
5508 it++;
5509 }
5510
5511 for (auto i = created.begin(); i != created.end(); i++) {
5512 auto j = i;
5513 for (j++; j != created.end(); j++) {
5514 std::set<ghobject_t> created_sub(i, j);
5515 objects.clear();
5516 ghobject_t next;
5517 r = collection_list(store, ch, *i, ghobject_t::get_max(),
5518 created_sub.size(), &objects, &next, disable_legacy);
5519 ASSERT_EQ(r, 0);
5520 ASSERT_EQ(created_sub.size(), objects.size());
5521 it = objects.begin();
5522 for (auto &hoid : created_sub) {
5523 ASSERT_EQ(hoid, *it);
5524 it++;
5525 }
5526 if (j == created.end()) {
5527 ASSERT_TRUE(next.is_max());
5528 } else {
5529 ASSERT_EQ(*j, next);
5530 }
5531 }
5532 }
5533
5534 for (auto i = created.begin(); i != created.end(); i++) {
5535 auto j = i;
5536 for (j++; j != created.end(); j++) {
5537 std::set<ghobject_t> created_sub(i, j);
5538 objects.clear();
5539 ghobject_t next;
5540 r = collection_list(store, ch, *i, *j, INT_MAX, &objects, &next,
5541 disable_legacy);
5542 ASSERT_EQ(r, 0);
5543 ASSERT_EQ(created_sub.size(), objects.size());
5544 it = objects.begin();
5545 for (auto &hoid : created_sub) {
5546 ASSERT_EQ(hoid, *it);
5547 it++;
5548 }
5549 if (j == created.end()) {
5550 ASSERT_TRUE(next.is_max());
5551 } else {
5552 ASSERT_EQ(*j, next);
5553 }
5554 }
5555 }
5556 }
5557
5558 TEST_P(StoreTest, ScrubTest) {
5559 int64_t poolid = 111;
5560 coll_t cid(spg_t(pg_t(0, poolid),shard_id_t(1)));
5561 int r;
5562 auto ch = store->create_new_collection(cid);
5563 {
5564 ObjectStore::Transaction t;
5565 t.create_collection(cid, 0);
5566 r = queue_transaction(store, ch, std::move(t));
5567 ASSERT_EQ(r, 0);
5568 }
5569 string base = "aaaaa";
5570 set<ghobject_t> created;
5571 for (int i = 0; i < 1000; ++i) {
5572 char buf[100];
5573 sprintf(buf, "%d", i);
5574 if (!(i % 5)) {
5575 cerr << "Object " << i << std::endl;
5576 }
5577 ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, i,
5578 poolid, ""),
5579 ghobject_t::NO_GEN, shard_id_t(1));
5580 {
5581 ObjectStore::Transaction t;
5582 t.touch(cid, hoid);
5583 r = queue_transaction(store, ch, std::move(t));
5584 ASSERT_EQ(r, 0);
5585 }
5586 created.insert(hoid);
5587 }
5588
5589 // Add same hobject_t but different generation
5590 {
5591 ghobject_t hoid1(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""),
5592 ghobject_t::NO_GEN, shard_id_t(1));
5593 ghobject_t hoid2(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)1, shard_id_t(1));
5594 ghobject_t hoid3(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)2, shard_id_t(1));
5595 ObjectStore::Transaction t;
5596 t.touch(cid, hoid1);
5597 t.touch(cid, hoid2);
5598 t.touch(cid, hoid3);
5599 r = queue_transaction(store, ch, std::move(t));
5600 created.insert(hoid1);
5601 created.insert(hoid2);
5602 created.insert(hoid3);
5603 ASSERT_EQ(r, 0);
5604 }
5605
5606 vector<ghobject_t> objects;
5607 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
5608 &objects, 0);
5609 ASSERT_EQ(r, 0);
5610 set<ghobject_t> listed(objects.begin(), objects.end());
5611 cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
5612 ASSERT_TRUE(listed.size() == created.size());
5613 objects.clear();
5614 listed.clear();
5615 ghobject_t current, next;
5616 while (1) {
5617 r = collection_list(store, ch, current, ghobject_t::get_max(), 60, &objects,
5618 &next);
5619 ASSERT_EQ(r, 0);
5620 ASSERT_TRUE(sorted(objects));
5621 for (vector<ghobject_t>::iterator i = objects.begin();
5622 i != objects.end(); ++i) {
5623 if (listed.count(*i))
5624 cerr << *i << " repeated" << std::endl;
5625 listed.insert(*i);
5626 }
5627 if (objects.size() < 50) {
5628 ASSERT_TRUE(next.is_max());
5629 break;
5630 }
5631 objects.clear();
5632 current = next.get_boundary();
5633 }
5634 cerr << "listed.size() is " << listed.size() << std::endl;
5635 ASSERT_TRUE(listed.size() == created.size());
5636 for (set<ghobject_t>::iterator i = listed.begin();
5637 i != listed.end();
5638 ++i) {
5639 ASSERT_TRUE(created.count(*i));
5640 }
5641
5642 for (set<ghobject_t>::iterator i = created.begin();
5643 i != created.end();
5644 ++i) {
5645 ObjectStore::Transaction t;
5646 t.remove(cid, *i);
5647 r = queue_transaction(store, ch, std::move(t));
5648 ASSERT_EQ(r, 0);
5649 }
5650 ObjectStore::Transaction t;
5651 t.remove_collection(cid);
5652 r = queue_transaction(store, ch, std::move(t));
5653 ASSERT_EQ(r, 0);
5654 }
5655
5656
5657 TEST_P(StoreTest, OMapTest) {
5658 coll_t cid;
5659 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
5660 auto ch = store->create_new_collection(cid);
5661 int r;
5662 {
5663 ObjectStore::Transaction t;
5664 t.create_collection(cid, 0);
5665 r = queue_transaction(store, ch, std::move(t));
5666 ASSERT_EQ(r, 0);
5667 }
5668
5669 map<string, bufferlist> attrs;
5670 {
5671 ObjectStore::Transaction t;
5672 t.touch(cid, hoid);
5673 t.omap_clear(cid, hoid);
5674 map<string, bufferlist> start_set;
5675 t.omap_setkeys(cid, hoid, start_set);
5676 r = queue_transaction(store, ch, std::move(t));
5677 ASSERT_EQ(r, 0);
5678 }
5679
5680 for (int i = 0; i < 100; i++) {
5681 if (!(i%5)) {
5682 std::cout << "On iteration " << i << std::endl;
5683 }
5684 ObjectStore::Transaction t;
5685 bufferlist bl;
5686 map<string, bufferlist> cur_attrs;
5687 r = store->omap_get(ch, hoid, &bl, &cur_attrs);
5688 ASSERT_EQ(r, 0);
5689 for (map<string, bufferlist>::iterator j = attrs.begin();
5690 j != attrs.end();
5691 ++j) {
5692 bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
5693 if (!correct) {
5694 std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
5695 if (cur_attrs.count(j->first) > 0) {
5696 std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
5697 }
5698 }
5699 ASSERT_EQ(correct, true);
5700 }
5701 ASSERT_EQ(attrs.size(), cur_attrs.size());
5702
5703 char buf[100];
5704 snprintf(buf, sizeof(buf), "%d", i);
5705 bl.clear();
5706 bufferptr bp(buf, strlen(buf) + 1);
5707 bl.append(bp);
5708 map<string, bufferlist> to_add;
5709 to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5710 attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5711 t.omap_setkeys(cid, hoid, to_add);
5712 r = queue_transaction(store, ch, std::move(t));
5713 ASSERT_EQ(r, 0);
5714 }
5715
5716 int i = 0;
5717 while (attrs.size()) {
5718 if (!(i%5)) {
5719 std::cout << "removal: On iteration " << i << std::endl;
5720 }
5721 ObjectStore::Transaction t;
5722 bufferlist bl;
5723 map<string, bufferlist> cur_attrs;
5724 r = store->omap_get(ch, hoid, &bl, &cur_attrs);
5725 ASSERT_EQ(r, 0);
5726 for (map<string, bufferlist>::iterator j = attrs.begin();
5727 j != attrs.end();
5728 ++j) {
5729 bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
5730 if (!correct) {
5731 std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
5732 if (cur_attrs.count(j->first) > 0) {
5733 std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
5734 }
5735 }
5736 ASSERT_EQ(correct, true);
5737 }
5738
5739 string to_remove = attrs.begin()->first;
5740 t.omap_rmkey(cid, hoid, to_remove);
5741 r = queue_transaction(store, ch, std::move(t));
5742 ASSERT_EQ(r, 0);
5743
5744 attrs.erase(to_remove);
5745
5746 ++i;
5747 }
5748
5749 {
5750 bufferlist bl1;
5751 bl1.append("omap_header");
5752 ObjectStore::Transaction t;
5753 t.omap_setheader(cid, hoid, bl1);
5754 r = queue_transaction(store, ch, std::move(t));
5755 ASSERT_EQ(r, 0);
5756 t = ObjectStore::Transaction();
5757
5758 bufferlist bl2;
5759 bl2.append("value");
5760 map<string, bufferlist> to_add;
5761 to_add.insert(pair<string, bufferlist>("key", bl2));
5762 t.omap_setkeys(cid, hoid, to_add);
5763 r = queue_transaction(store, ch, std::move(t));
5764 ASSERT_EQ(r, 0);
5765
5766 bufferlist bl3;
5767 map<string, bufferlist> cur_attrs;
5768 r = store->omap_get(ch, hoid, &bl3, &cur_attrs);
5769 ASSERT_EQ(r, 0);
5770 ASSERT_EQ(cur_attrs.size(), size_t(1));
5771 ASSERT_TRUE(bl_eq(bl1, bl3));
5772
5773 set<string> keys;
5774 r = store->omap_get_keys(ch, hoid, &keys);
5775 ASSERT_EQ(r, 0);
5776 ASSERT_EQ(keys.size(), size_t(1));
5777 }
5778
5779 // test omap_clear, omap_rmkey_range
5780 {
5781 {
5782 map<string,bufferlist> to_set;
5783 for (int n=0; n<10; ++n) {
5784 to_set[stringify(n)].append("foo");
5785 }
5786 bufferlist h;
5787 h.append("header");
5788 ObjectStore::Transaction t;
5789 t.remove(cid, hoid);
5790 t.touch(cid, hoid);
5791 t.omap_setheader(cid, hoid, h);
5792 t.omap_setkeys(cid, hoid, to_set);
5793 r = queue_transaction(store, ch, std::move(t));
5794 ASSERT_EQ(r, 0);
5795 }
5796 {
5797 ObjectStore::Transaction t;
5798 t.omap_rmkeyrange(cid, hoid, "3", "7");
5799 r = queue_transaction(store, ch, std::move(t));
5800 ASSERT_EQ(r, 0);
5801 }
5802 {
5803 bufferlist hdr;
5804 map<string,bufferlist> m;
5805 store->omap_get(ch, hoid, &hdr, &m);
5806 ASSERT_EQ(6u, hdr.length());
5807 ASSERT_TRUE(m.count("2"));
5808 ASSERT_TRUE(!m.count("3"));
5809 ASSERT_TRUE(!m.count("6"));
5810 ASSERT_TRUE(m.count("7"));
5811 ASSERT_TRUE(m.count("8"));
5812 //cout << m << std::endl;
5813 ASSERT_EQ(6u, m.size());
5814 }
5815 {
5816 ObjectStore::Transaction t;
5817 t.omap_clear(cid, hoid);
5818 r = queue_transaction(store, ch, std::move(t));
5819 ASSERT_EQ(r, 0);
5820 }
5821 {
5822 bufferlist hdr;
5823 map<string,bufferlist> m;
5824 store->omap_get(ch, hoid, &hdr, &m);
5825 ASSERT_EQ(0u, hdr.length());
5826 ASSERT_EQ(0u, m.size());
5827 }
5828 }
5829
5830 ObjectStore::Transaction t;
5831 t.remove(cid, hoid);
5832 t.remove_collection(cid);
5833 r = queue_transaction(store, ch, std::move(t));
5834 ASSERT_EQ(r, 0);
5835 }
5836
5837 TEST_P(StoreTest, OMapIterator) {
5838 coll_t cid;
5839 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
5840 int count = 0;
5841 auto ch = store->create_new_collection(cid);
5842 int r;
5843 {
5844 ObjectStore::Transaction t;
5845 t.create_collection(cid, 0);
5846 r = queue_transaction(store, ch, std::move(t));
5847 ASSERT_EQ(r, 0);
5848 }
5849
5850 map<string, bufferlist> attrs;
5851 {
5852 ObjectStore::Transaction t;
5853 t.touch(cid, hoid);
5854 t.omap_clear(cid, hoid);
5855 map<string, bufferlist> start_set;
5856 t.omap_setkeys(cid, hoid, start_set);
5857 r = queue_transaction(store, ch, std::move(t));
5858 ASSERT_EQ(r, 0);
5859 }
5860 ObjectMap::ObjectMapIterator iter;
5861 bool correct;
5862 //basic iteration
5863 for (int i = 0; i < 100; i++) {
5864 if (!(i%5)) {
5865 std::cout << "On iteration " << i << std::endl;
5866 }
5867 bufferlist bl;
5868
5869 // FileStore may deadlock two active iterators over the same data
5870 iter = ObjectMap::ObjectMapIterator();
5871
5872 iter = store->get_omap_iterator(ch, hoid);
5873 for (iter->seek_to_first(), count=0; iter->valid(); iter->next(), count++) {
5874 string key = iter->key();
5875 bufferlist value = iter->value();
5876 correct = attrs.count(key) && (string(value.c_str()) == string(attrs[key].c_str()));
5877 if (!correct) {
5878 if (attrs.count(key) > 0) {
5879 std::cout << "key " << key << "in omap , " << value.c_str() << " : " << attrs[key].c_str() << std::endl;
5880 }
5881 else
5882 std::cout << "key " << key << "should not exists in omap" << std::endl;
5883 }
5884 ASSERT_EQ(correct, true);
5885 }
5886 ASSERT_EQ((int)attrs.size(), count);
5887
5888 // FileStore may deadlock an active iterator vs queue_transaction
5889 iter = ObjectMap::ObjectMapIterator();
5890
5891 char buf[100];
5892 snprintf(buf, sizeof(buf), "%d", i);
5893 bl.clear();
5894 bufferptr bp(buf, strlen(buf) + 1);
5895 bl.append(bp);
5896 map<string, bufferlist> to_add;
5897 to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5898 attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
5899 ObjectStore::Transaction t;
5900 t.omap_setkeys(cid, hoid, to_add);
5901 r = queue_transaction(store, ch, std::move(t));
5902 ASSERT_EQ(r, 0);
5903 }
5904
5905 iter = store->get_omap_iterator(ch, hoid);
5906 //lower bound
5907 string bound_key = "key-5";
5908 iter->lower_bound(bound_key);
5909 correct = bound_key <= iter->key();
5910 if (!correct) {
5911 std::cout << "lower bound, bound key is " << bound_key << " < iter key is " << iter->key() << std::endl;
5912 }
5913 ASSERT_EQ(correct, true);
5914 //upper bound
5915 iter->upper_bound(bound_key);
5916 correct = iter->key() > bound_key;
5917 if (!correct) {
5918 std::cout << "upper bound, bound key is " << bound_key << " >= iter key is " << iter->key() << std::endl;
5919 }
5920 ASSERT_EQ(correct, true);
5921
5922 // FileStore may deadlock an active iterator vs queue_transaction
5923 iter = ObjectMap::ObjectMapIterator();
5924 {
5925 ObjectStore::Transaction t;
5926 t.remove(cid, hoid);
5927 t.remove_collection(cid);
5928 r = queue_transaction(store, ch, std::move(t));
5929 ASSERT_EQ(r, 0);
5930 }
5931 }
5932
5933 TEST_P(StoreTest, XattrTest) {
5934 coll_t cid;
5935 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
5936 bufferlist big;
5937 for (unsigned i = 0; i < 10000; ++i) {
5938 big.append('\0');
5939 }
5940 bufferlist small;
5941 for (unsigned i = 0; i < 10; ++i) {
5942 small.append('\0');
5943 }
5944 int r;
5945 auto ch = store->create_new_collection(cid);
5946 {
5947 ObjectStore::Transaction t;
5948 t.create_collection(cid, 0);
5949 t.touch(cid, hoid);
5950 r = queue_transaction(store, ch, std::move(t));
5951 ASSERT_EQ(r, 0);
5952 }
5953
5954 map<string, bufferlist> attrs;
5955 {
5956 ObjectStore::Transaction t;
5957 t.setattr(cid, hoid, "attr1", small);
5958 attrs["attr1"] = small;
5959 t.setattr(cid, hoid, "attr2", big);
5960 attrs["attr2"] = big;
5961 t.setattr(cid, hoid, "attr3", small);
5962 attrs["attr3"] = small;
5963 t.setattr(cid, hoid, "attr1", small);
5964 attrs["attr1"] = small;
5965 t.setattr(cid, hoid, "attr4", big);
5966 attrs["attr4"] = big;
5967 t.setattr(cid, hoid, "attr3", big);
5968 attrs["attr3"] = big;
5969 r = queue_transaction(store, ch, std::move(t));
5970 ASSERT_EQ(r, 0);
5971 }
5972
5973 map<string, bufferptr, less<>> aset;
5974 store->getattrs(ch, hoid, aset);
5975 ASSERT_EQ(aset.size(), attrs.size());
5976 for (map<string, bufferptr>::iterator i = aset.begin();
5977 i != aset.end();
5978 ++i) {
5979 bufferlist bl;
5980 bl.push_back(i->second);
5981 ASSERT_TRUE(attrs[i->first] == bl);
5982 }
5983
5984 {
5985 ObjectStore::Transaction t;
5986 t.rmattr(cid, hoid, "attr2");
5987 attrs.erase("attr2");
5988 r = queue_transaction(store, ch, std::move(t));
5989 ASSERT_EQ(r, 0);
5990 }
5991
5992 aset.clear();
5993 store->getattrs(ch, hoid, aset);
5994 ASSERT_EQ(aset.size(), attrs.size());
5995 for (map<string, bufferptr>::iterator i = aset.begin();
5996 i != aset.end();
5997 ++i) {
5998 bufferlist bl;
5999 bl.push_back(i->second);
6000 ASSERT_TRUE(attrs[i->first] == bl);
6001 }
6002
6003 bufferptr bp;
6004 r = store->getattr(ch, hoid, "attr2", bp);
6005 ASSERT_EQ(r, -ENODATA);
6006
6007 r = store->getattr(ch, hoid, "attr3", bp);
6008 ASSERT_EQ(r, 0);
6009 bufferlist bl2;
6010 bl2.push_back(bp);
6011 ASSERT_TRUE(bl2 == attrs["attr3"]);
6012
6013 ObjectStore::Transaction t;
6014 t.remove(cid, hoid);
6015 t.remove_collection(cid);
6016 r = queue_transaction(store, ch, std::move(t));
6017 ASSERT_EQ(r, 0);
6018 }
6019
6020 void colsplittest(
6021 ObjectStore *store,
6022 unsigned num_objects,
6023 unsigned common_suffix_size,
6024 bool clones
6025 ) {
6026 coll_t cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD));
6027 coll_t tid(spg_t(pg_t(1<<common_suffix_size,52),shard_id_t::NO_SHARD));
6028 auto ch = store->create_new_collection(cid);
6029 auto tch = store->create_new_collection(tid);
6030 int r = 0;
6031 {
6032 ObjectStore::Transaction t;
6033 t.create_collection(cid, common_suffix_size);
6034 r = queue_transaction(store, ch, std::move(t));
6035 ASSERT_EQ(r, 0);
6036 }
6037 bufferlist small;
6038 small.append("small");
6039 {
6040 ObjectStore::Transaction t;
6041 for (uint32_t i = 0; i < (2 - (int)clones)*num_objects; ++i) {
6042 stringstream objname;
6043 objname << "obj" << i;
6044 ghobject_t a(hobject_t(
6045 objname.str(),
6046 "",
6047 CEPH_NOSNAP,
6048 i<<common_suffix_size,
6049 52, ""));
6050 t.write(cid, a, 0, small.length(), small,
6051 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6052 if (clones) {
6053 objname << "-clone";
6054 ghobject_t b(hobject_t(
6055 objname.str(),
6056 "",
6057 CEPH_NOSNAP,
6058 i<<common_suffix_size,
6059 52, ""));
6060 t.clone(cid, a, b);
6061 }
6062 if (i % 100) {
6063 r = queue_transaction(store, ch, std::move(t));
6064 ASSERT_EQ(r, 0);
6065 t = ObjectStore::Transaction();
6066 }
6067 }
6068 r = queue_transaction(store, ch, std::move(t));
6069 ASSERT_EQ(r, 0);
6070 }
6071 {
6072 ObjectStore::Transaction t;
6073 t.create_collection(tid, common_suffix_size + 1);
6074 t.split_collection(cid, common_suffix_size+1, 1<<common_suffix_size, tid);
6075 r = queue_transaction(store, ch, std::move(t));
6076 ASSERT_EQ(r, 0);
6077 }
6078 ch->flush();
6079
6080 // check
6081 vector<ghobject_t> objects;
6082 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
6083 &objects, 0);
6084 ASSERT_EQ(r, 0);
6085 ASSERT_EQ(objects.size(), num_objects);
6086 for (vector<ghobject_t>::iterator i = objects.begin();
6087 i != objects.end();
6088 ++i) {
6089 ASSERT_EQ(!!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
6090 }
6091
6092 objects.clear();
6093 r = collection_list(store, tch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
6094 &objects, 0);
6095 ASSERT_EQ(r, 0);
6096 ASSERT_EQ(objects.size(), num_objects);
6097 for (vector<ghobject_t>::iterator i = objects.begin();
6098 i != objects.end();
6099 ++i) {
6100 ASSERT_EQ(!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
6101 }
6102
6103 // merge them again!
6104 {
6105 ObjectStore::Transaction t;
6106 t.merge_collection(tid, cid, common_suffix_size);
6107 r = queue_transaction(store, ch, std::move(t));
6108 ASSERT_EQ(r, 0);
6109 }
6110
6111 // check and clean up
6112 ObjectStore::Transaction t;
6113 {
6114 vector<ghobject_t> objects;
6115 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
6116 &objects, 0);
6117 ASSERT_EQ(r, 0);
6118 ASSERT_EQ(objects.size(), num_objects * 2); // both halves
6119 unsigned size = 0;
6120 for (vector<ghobject_t>::iterator i = objects.begin();
6121 i != objects.end();
6122 ++i) {
6123 t.remove(cid, *i);
6124 if (++size > 100) {
6125 size = 0;
6126 r = queue_transaction(store, ch, std::move(t));
6127 ASSERT_EQ(r, 0);
6128 t = ObjectStore::Transaction();
6129 }
6130 }
6131 }
6132 t.remove_collection(cid);
6133 r = queue_transaction(store, ch, std::move(t));
6134 ASSERT_EQ(r, 0);
6135
6136 ch->flush();
6137 ASSERT_TRUE(!store->collection_exists(tid));
6138 }
6139
6140 TEST_P(StoreTest, ColSplitTest0) {
6141 colsplittest(store.get(), 10, 5, false);
6142 }
6143 TEST_P(StoreTest, ColSplitTest1) {
6144 colsplittest(store.get(), 10000, 11, false);
6145 }
6146 TEST_P(StoreTest, ColSplitTest1Clones) {
6147 colsplittest(store.get(), 10000, 11, true);
6148 }
6149 TEST_P(StoreTest, ColSplitTest2) {
6150 colsplittest(store.get(), 100, 7, false);
6151 }
6152 TEST_P(StoreTest, ColSplitTest2Clones) {
6153 colsplittest(store.get(), 100, 7, true);
6154 }
6155
6156 #if 0
6157 TEST_P(StoreTest, ColSplitTest3) {
6158 colsplittest(store.get(), 100000, 25);
6159 }
6160 #endif
6161
6162 void test_merge_skewed(ObjectStore *store,
6163 unsigned base, unsigned bits,
6164 unsigned anum, unsigned bnum)
6165 {
6166 cout << __func__ << " 0x" << std::hex << base << std::dec
6167 << " bits " << bits
6168 << " anum " << anum << " bnum " << bnum << std::endl;
6169 /*
6170 make merge source pgs have radically different # of objects in them,
6171 which should trigger different splitting in filestore, and verify that
6172 post-merge all objects are accessible.
6173 */
6174 int r;
6175 coll_t a(spg_t(pg_t(base, 0), shard_id_t::NO_SHARD));
6176 coll_t b(spg_t(pg_t(base | (1<<bits), 0), shard_id_t::NO_SHARD));
6177
6178 auto cha = store->create_new_collection(a);
6179 auto chb = store->create_new_collection(b);
6180 {
6181 ObjectStore::Transaction t;
6182 t.create_collection(a, bits + 1);
6183 r = queue_transaction(store, cha, std::move(t));
6184 ASSERT_EQ(r, 0);
6185 }
6186 {
6187 ObjectStore::Transaction t;
6188 t.create_collection(b, bits + 1);
6189 r = queue_transaction(store, chb, std::move(t));
6190 ASSERT_EQ(r, 0);
6191 }
6192
6193 bufferlist small;
6194 small.append("small");
6195 string suffix = "ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooaaaaaaaaaa";
6196 set<ghobject_t> aobjects, bobjects;
6197 {
6198 // fill a
6199 ObjectStore::Transaction t;
6200 for (unsigned i = 0; i < 1000; ++i) {
6201 string objname = "a" + stringify(i) + suffix;
6202 ghobject_t o(hobject_t(
6203 objname,
6204 "",
6205 CEPH_NOSNAP,
6206 i<<(bits+1) | base,
6207 52, ""));
6208 aobjects.insert(o);
6209 t.write(a, o, 0, small.length(), small, 0);
6210 if (i % 100) {
6211 r = queue_transaction(store, cha, std::move(t));
6212 ASSERT_EQ(r, 0);
6213 t = ObjectStore::Transaction();
6214 }
6215 }
6216 r = queue_transaction(store, cha, std::move(t));
6217 ASSERT_EQ(r, 0);
6218 }
6219 {
6220 // fill b
6221 ObjectStore::Transaction t;
6222 for (unsigned i = 0; i < 10; ++i) {
6223 string objname = "b" + stringify(i) + suffix;
6224 ghobject_t o(hobject_t(
6225 objname,
6226 "",
6227 CEPH_NOSNAP,
6228 (i<<(base+1)) | base | (1<<bits),
6229 52, ""));
6230 bobjects.insert(o);
6231 t.write(b, o, 0, small.length(), small, 0);
6232 if (i % 100) {
6233 r = queue_transaction(store, chb, std::move(t));
6234 ASSERT_EQ(r, 0);
6235 t = ObjectStore::Transaction();
6236 }
6237 }
6238 r = queue_transaction(store, chb, std::move(t));
6239 ASSERT_EQ(r, 0);
6240 }
6241
6242 // merge b->a
6243 {
6244 ObjectStore::Transaction t;
6245 t.merge_collection(b, a, bits);
6246 r = queue_transaction(store, cha, std::move(t));
6247 ASSERT_EQ(r, 0);
6248 }
6249
6250 // verify
6251 {
6252 vector<ghobject_t> got;
6253 collection_list(store, cha, ghobject_t(), ghobject_t::get_max(), INT_MAX,
6254 &got, 0);
6255 set<ghobject_t> gotset;
6256 for (auto& o : got) {
6257 ASSERT_TRUE(aobjects.count(o) || bobjects.count(o));
6258 gotset.insert(o);
6259 }
6260 // check both listing and stat-ability (different code paths!)
6261 struct stat st;
6262 for (auto& o : aobjects) {
6263 ASSERT_TRUE(gotset.count(o));
6264 int r = store->stat(cha, o, &st, false);
6265 ASSERT_EQ(r, 0);
6266 }
6267 for (auto& o : bobjects) {
6268 ASSERT_TRUE(gotset.count(o));
6269 int r = store->stat(cha, o, &st, false);
6270 ASSERT_EQ(r, 0);
6271 }
6272 }
6273
6274 // clean up
6275 {
6276 ObjectStore::Transaction t;
6277 for (auto &o : aobjects) {
6278 t.remove(a, o);
6279 }
6280 r = queue_transaction(store, cha, std::move(t));
6281 ASSERT_EQ(r, 0);
6282 }
6283 {
6284 ObjectStore::Transaction t;
6285 for (auto &o : bobjects) {
6286 t.remove(a, o);
6287 }
6288 t.remove_collection(a);
6289 r = queue_transaction(store, cha, std::move(t));
6290 ASSERT_EQ(r, 0);
6291 }
6292 }
6293
6294 TEST_P(StoreTest, MergeSkewed) {
6295 if (string(GetParam()) != "filestore")
6296 return;
6297
6298 // this is sufficient to exercise merges with different hashing levels
6299 test_merge_skewed(store.get(), 0xf, 4, 10, 10000);
6300 test_merge_skewed(store.get(), 0xf, 4, 10000, 10);
6301
6302 /*
6303 // this covers a zillion variations that all boil down to the same thing
6304 for (unsigned base = 3; base < 0x1000; base *= 5) {
6305 unsigned bits;
6306 unsigned t = base;
6307 for (bits = 0; t; t >>= 1) {
6308 ++bits;
6309 }
6310 for (unsigned b = bits; b < bits + 10; b += 3) {
6311 for (auto anum : { 10, 1000, 10000 }) {
6312 for (auto bnum : { 10, 1000, 10000 }) {
6313 if (anum == bnum) {
6314 continue;
6315 }
6316 test_merge_skewed(store.get(), base, b, anum, bnum);
6317 }
6318 }
6319 }
6320 }
6321 */
6322 }
6323
6324
6325 /**
6326 * This test tests adding two different groups
6327 * of objects, each with 1 common prefix and 1
6328 * different prefix. We then remove half
6329 * in order to verify that the merging correctly
6330 * stops at the common prefix subdir. See bug
6331 * #5273 */
6332 TEST_P(StoreTest, TwoHash) {
6333 coll_t cid;
6334 int r;
6335 auto ch = store->create_new_collection(cid);
6336 {
6337 ObjectStore::Transaction t;
6338 t.create_collection(cid, 0);
6339 r = queue_transaction(store, ch, std::move(t));
6340 ASSERT_EQ(r, 0);
6341 }
6342 std::cout << "Making objects" << std::endl;
6343 for (int i = 0; i < 360; ++i) {
6344 ObjectStore::Transaction t;
6345 ghobject_t o;
6346 o.hobj.pool = -1;
6347 if (i < 8) {
6348 o.hobj.set_hash((i << 16) | 0xA1);
6349 t.touch(cid, o);
6350 }
6351 o.hobj.set_hash((i << 16) | 0xB1);
6352 t.touch(cid, o);
6353 r = queue_transaction(store, ch, std::move(t));
6354 ASSERT_EQ(r, 0);
6355 }
6356 std::cout << "Removing half" << std::endl;
6357 for (int i = 1; i < 8; ++i) {
6358 ObjectStore::Transaction t;
6359 ghobject_t o;
6360 o.hobj.pool = -1;
6361 o.hobj.set_hash((i << 16) | 0xA1);
6362 t.remove(cid, o);
6363 r = queue_transaction(store, ch, std::move(t));
6364 ASSERT_EQ(r, 0);
6365 }
6366 std::cout << "Checking" << std::endl;
6367 for (int i = 1; i < 8; ++i) {
6368 ObjectStore::Transaction t;
6369 ghobject_t o;
6370 o.hobj.set_hash((i << 16) | 0xA1);
6371 o.hobj.pool = -1;
6372 bool exists = store->exists(ch, o);
6373 ASSERT_EQ(exists, false);
6374 }
6375 {
6376 ghobject_t o;
6377 o.hobj.set_hash(0xA1);
6378 o.hobj.pool = -1;
6379 bool exists = store->exists(ch, o);
6380 ASSERT_EQ(exists, true);
6381 }
6382 std::cout << "Cleanup" << std::endl;
6383 for (int i = 0; i < 360; ++i) {
6384 ObjectStore::Transaction t;
6385 ghobject_t o;
6386 o.hobj.set_hash((i << 16) | 0xA1);
6387 o.hobj.pool = -1;
6388 t.remove(cid, o);
6389 o.hobj.set_hash((i << 16) | 0xB1);
6390 t.remove(cid, o);
6391 r = queue_transaction(store, ch, std::move(t));
6392 ASSERT_EQ(r, 0);
6393 }
6394 ObjectStore::Transaction t;
6395 t.remove_collection(cid);
6396 r = queue_transaction(store, ch, std::move(t));
6397 ASSERT_EQ(r, 0);
6398 }
6399
6400 TEST_P(StoreTest, Rename) {
6401 coll_t cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD));
6402 ghobject_t srcoid(hobject_t("src_oid", "", CEPH_NOSNAP, 0, 0, ""));
6403 ghobject_t dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
6404 bufferlist a, b;
6405 a.append("foo");
6406 b.append("bar");
6407 auto ch = store->create_new_collection(cid);
6408 int r;
6409 {
6410 ObjectStore::Transaction t;
6411 t.create_collection(cid, 0);
6412 t.write(cid, srcoid, 0, a.length(), a);
6413 r = queue_transaction(store, ch, std::move(t));
6414 ASSERT_EQ(r, 0);
6415 }
6416 ASSERT_TRUE(store->exists(ch, srcoid));
6417 {
6418 ObjectStore::Transaction t;
6419 t.collection_move_rename(cid, srcoid, cid, dstoid);
6420 t.write(cid, srcoid, 0, b.length(), b);
6421 t.setattr(cid, srcoid, "attr", b);
6422 r = queue_transaction(store, ch, std::move(t));
6423 ASSERT_EQ(r, 0);
6424 }
6425 ASSERT_TRUE(store->exists(ch, srcoid));
6426 ASSERT_TRUE(store->exists(ch, dstoid));
6427 {
6428 bufferlist bl;
6429 store->read(ch, srcoid, 0, 3, bl);
6430 ASSERT_TRUE(bl_eq(b, bl));
6431 store->read(ch, dstoid, 0, 3, bl);
6432 ASSERT_TRUE(bl_eq(a, bl));
6433 }
6434 {
6435 ObjectStore::Transaction t;
6436 t.remove(cid, dstoid);
6437 t.collection_move_rename(cid, srcoid, cid, dstoid);
6438 r = queue_transaction(store, ch, std::move(t));
6439 ASSERT_EQ(r, 0);
6440 }
6441 ASSERT_TRUE(store->exists(ch, dstoid));
6442 ASSERT_FALSE(store->exists(ch, srcoid));
6443 {
6444 bufferlist bl;
6445 store->read(ch, dstoid, 0, 3, bl);
6446 ASSERT_TRUE(bl_eq(b, bl));
6447 }
6448 {
6449 ObjectStore::Transaction t;
6450 t.remove(cid, dstoid);
6451 t.remove_collection(cid);
6452 r = queue_transaction(store, ch, std::move(t));
6453 ASSERT_EQ(r, 0);
6454 }
6455 }
6456
6457 TEST_P(StoreTest, MoveRename) {
6458 coll_t cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD));
6459 ghobject_t temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP, 0, 0, ""));
6460 ghobject_t oid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
6461 auto ch = store->create_new_collection(cid);
6462 int r;
6463 {
6464 ObjectStore::Transaction t;
6465 t.create_collection(cid, 0);
6466 t.touch(cid, oid);
6467 r = queue_transaction(store, ch, std::move(t));
6468 ASSERT_EQ(r, 0);
6469 }
6470 ASSERT_TRUE(store->exists(ch, oid));
6471 bufferlist data, attr;
6472 map<string, bufferlist> omap;
6473 data.append("data payload");
6474 attr.append("attr value");
6475 omap["omap_key"].append("omap value");
6476 {
6477 ObjectStore::Transaction t;
6478 t.touch(cid, temp_oid);
6479 t.write(cid, temp_oid, 0, data.length(), data);
6480 t.setattr(cid, temp_oid, "attr", attr);
6481 t.omap_setkeys(cid, temp_oid, omap);
6482 r = queue_transaction(store, ch, std::move(t));
6483 ASSERT_EQ(r, 0);
6484 }
6485 ASSERT_TRUE(store->exists(ch, temp_oid));
6486 {
6487 ObjectStore::Transaction t;
6488 t.remove(cid, oid);
6489 t.collection_move_rename(cid, temp_oid, cid, oid);
6490 r = queue_transaction(store, ch, std::move(t));
6491 ASSERT_EQ(r, 0);
6492 }
6493 ASSERT_TRUE(store->exists(ch, oid));
6494 ASSERT_FALSE(store->exists(ch, temp_oid));
6495 {
6496 bufferlist newdata;
6497 r = store->read(ch, oid, 0, 1000, newdata);
6498 ASSERT_GE(r, 0);
6499 ASSERT_TRUE(bl_eq(data, newdata));
6500 bufferlist newattr;
6501 r = store->getattr(ch, oid, "attr", newattr);
6502 ASSERT_EQ(r, 0);
6503 ASSERT_TRUE(bl_eq(attr, newattr));
6504 set<string> keys;
6505 keys.insert("omap_key");
6506 map<string, bufferlist> newomap;
6507 r = store->omap_get_values(ch, oid, keys, &newomap);
6508 ASSERT_GE(r, 0);
6509 ASSERT_EQ(1u, newomap.size());
6510 ASSERT_TRUE(newomap.count("omap_key"));
6511 ASSERT_TRUE(bl_eq(omap["omap_key"], newomap["omap_key"]));
6512 }
6513 {
6514 ObjectStore::Transaction t;
6515 t.remove(cid, oid);
6516 t.remove_collection(cid);
6517 r = queue_transaction(store, ch, std::move(t));
6518 ASSERT_EQ(r, 0);
6519 }
6520 }
6521
6522 TEST_P(StoreTest, BigRGWObjectName) {
6523 coll_t cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD));
6524 ghobject_t oid(
6525 hobject_t(
6526 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
6527 "",
6528 CEPH_NOSNAP,
6529 0x81920472,
6530 12,
6531 ""),
6532 15,
6533 shard_id_t::NO_SHARD);
6534 ghobject_t oid2(oid);
6535 oid2.generation = 17;
6536 ghobject_t oidhead(oid);
6537 oidhead.generation = ghobject_t::NO_GEN;
6538
6539 auto ch = store->create_new_collection(cid);
6540
6541 int r;
6542 {
6543 ObjectStore::Transaction t;
6544 t.create_collection(cid, 0);
6545 t.touch(cid, oidhead);
6546 t.collection_move_rename(cid, oidhead, cid, oid);
6547 t.touch(cid, oidhead);
6548 t.collection_move_rename(cid, oidhead, cid, oid2);
6549 r = queue_transaction(store, ch, std::move(t));
6550 ASSERT_EQ(r, 0);
6551 }
6552
6553 {
6554 ObjectStore::Transaction t;
6555 t.remove(cid, oid);
6556 r = queue_transaction(store, ch, std::move(t));
6557 ASSERT_EQ(r, 0);
6558 }
6559
6560 {
6561 vector<ghobject_t> objects;
6562 r = collection_list(store, ch, ghobject_t(), ghobject_t::get_max(), INT_MAX,
6563 &objects, 0);
6564 ASSERT_EQ(r, 0);
6565 ASSERT_EQ(objects.size(), 1u);
6566 ASSERT_EQ(objects[0], oid2);
6567 }
6568
6569 ASSERT_FALSE(store->exists(ch, oid));
6570
6571 {
6572 ObjectStore::Transaction t;
6573 t.remove(cid, oid2);
6574 t.remove_collection(cid);
6575 r = queue_transaction(store, ch, std::move(t));
6576 ASSERT_EQ(r, 0);
6577
6578 }
6579 }
6580
6581 TEST_P(StoreTest, SetAllocHint) {
6582 coll_t cid;
6583 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, 0, ""));
6584 auto ch = store->create_new_collection(cid);
6585 int r;
6586 {
6587 ObjectStore::Transaction t;
6588 t.create_collection(cid, 0);
6589 t.touch(cid, hoid);
6590 r = queue_transaction(store, ch, std::move(t));
6591 ASSERT_EQ(r, 0);
6592 }
6593 {
6594 ObjectStore::Transaction t;
6595 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
6596 r = queue_transaction(store, ch, std::move(t));
6597 ASSERT_EQ(r, 0);
6598 }
6599 {
6600 ObjectStore::Transaction t;
6601 t.remove(cid, hoid);
6602 r = queue_transaction(store, ch, std::move(t));
6603 ASSERT_EQ(r, 0);
6604 }
6605 {
6606 ObjectStore::Transaction t;
6607 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
6608 r = queue_transaction(store, ch, std::move(t));
6609 ASSERT_EQ(r, 0);
6610 }
6611 {
6612 ObjectStore::Transaction t;
6613 t.remove_collection(cid);
6614 r = queue_transaction(store, ch, std::move(t));
6615 ASSERT_EQ(r, 0);
6616 }
6617 }
6618
6619 TEST_P(StoreTest, TryMoveRename) {
6620 coll_t cid;
6621 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6622 ghobject_t hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP, 0, -1, ""));
6623 auto ch = store->create_new_collection(cid);
6624 int r;
6625 {
6626 ObjectStore::Transaction t;
6627 t.create_collection(cid, 0);
6628 r = queue_transaction(store, ch, std::move(t));
6629 ASSERT_EQ(r, 0);
6630 }
6631 {
6632 ObjectStore::Transaction t;
6633 t.try_rename(cid, hoid, hoid2);
6634 r = queue_transaction(store, ch, std::move(t));
6635 ASSERT_EQ(r, 0);
6636 }
6637 {
6638 ObjectStore::Transaction t;
6639 t.touch(cid, hoid);
6640 r = queue_transaction(store, ch, std::move(t));
6641 ASSERT_EQ(r, 0);
6642 }
6643 {
6644 ObjectStore::Transaction t;
6645 t.try_rename(cid, hoid, hoid2);
6646 r = queue_transaction(store, ch, std::move(t));
6647 ASSERT_EQ(r, 0);
6648 }
6649 struct stat st;
6650 ASSERT_EQ(store->stat(ch, hoid, &st), -ENOENT);
6651 ASSERT_EQ(store->stat(ch, hoid2, &st), 0);
6652 }
6653
6654 #if defined(WITH_BLUESTORE)
6655 TEST_P(StoreTest, BluestoreOnOffCSumTest) {
6656 if (string(GetParam()) != "bluestore")
6657 return;
6658 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6659 g_conf().apply_changes(nullptr);
6660
6661 int r;
6662 coll_t cid;
6663 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
6664 {
6665 auto ch = store->open_collection(cid);
6666 ASSERT_FALSE(ch);
6667 }
6668 auto ch = store->create_new_collection(cid);
6669 {
6670 ObjectStore::Transaction t;
6671 t.create_collection(cid, 0);
6672 cerr << "Creating collection " << cid << std::endl;
6673 r = queue_transaction(store, ch, std::move(t));
6674 ASSERT_EQ(r, 0);
6675 }
6676 {
6677 //write with csum enabled followed by read with csum disabled
6678 size_t block_size = 64*1024;
6679 ObjectStore::Transaction t;
6680 bufferlist bl, orig;
6681 bl.append(std::string(block_size, 'a'));
6682 orig = bl;
6683 t.remove(cid, hoid);
6684 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
6685 t.write(cid, hoid, 0, bl.length(), bl);
6686 cerr << "Remove then create" << std::endl;
6687 r = queue_transaction(store, ch, std::move(t));
6688 ASSERT_EQ(r, 0);
6689
6690 SetVal(g_conf(), "bluestore_csum_type", "none");
6691 g_conf().apply_changes(nullptr);
6692
6693 bufferlist in;
6694 r = store->read(ch, hoid, 0, block_size, in);
6695 ASSERT_EQ((int)block_size, r);
6696 ASSERT_TRUE(bl_eq(orig, in));
6697
6698 }
6699 {
6700 //write with csum disabled followed by read with csum enabled
6701
6702 size_t block_size = 64*1024;
6703 ObjectStore::Transaction t;
6704 bufferlist bl, orig;
6705 bl.append(std::string(block_size, 'a'));
6706 orig = bl;
6707 t.remove(cid, hoid);
6708 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
6709 t.write(cid, hoid, 0, bl.length(), bl);
6710 cerr << "Remove then create" << std::endl;
6711 r = queue_transaction(store, ch, std::move(t));
6712 ASSERT_EQ(r, 0);
6713
6714 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6715 g_conf().apply_changes(nullptr);
6716
6717 bufferlist in;
6718 r = store->read(ch, hoid, 0, block_size, in);
6719 ASSERT_EQ((int)block_size, r);
6720 ASSERT_TRUE(bl_eq(orig, in));
6721 }
6722 {
6723 //'mixed' non-overlapping writes to the same blob
6724
6725 ObjectStore::Transaction t;
6726 bufferlist bl, orig;
6727 size_t block_size = 8000;
6728 bl.append(std::string(block_size, 'a'));
6729 orig = bl;
6730 t.remove(cid, hoid);
6731 t.write(cid, hoid, 0, bl.length(), bl);
6732 cerr << "Remove then create" << std::endl;
6733 r = queue_transaction(store, ch, std::move(t));
6734 ASSERT_EQ(r, 0);
6735
6736 SetVal(g_conf(), "bluestore_csum_type", "none");
6737 g_conf().apply_changes(nullptr);
6738
6739 ObjectStore::Transaction t2;
6740 t2.write(cid, hoid, block_size*2, bl.length(), bl);
6741 cerr << "Append 'unprotected'" << std::endl;
6742 r = queue_transaction(store, ch, std::move(t2));
6743 ASSERT_EQ(r, 0);
6744
6745 bufferlist in;
6746 r = store->read(ch, hoid, 0, block_size, in);
6747 ASSERT_EQ((int)block_size, r);
6748 ASSERT_TRUE(bl_eq(orig, in));
6749 in.clear();
6750 r = store->read(ch, hoid, block_size*2, block_size, in);
6751 ASSERT_EQ((int)block_size, r);
6752 ASSERT_TRUE(bl_eq(orig, in));
6753
6754 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6755 g_conf().apply_changes(nullptr);
6756 in.clear();
6757 r = store->read(ch, hoid, 0, block_size, in);
6758 ASSERT_EQ((int)block_size, r);
6759 ASSERT_TRUE(bl_eq(orig, in));
6760 in.clear();
6761 r = store->read(ch, hoid, block_size*2, block_size, in);
6762 ASSERT_EQ((int)block_size, r);
6763 ASSERT_TRUE(bl_eq(orig, in));
6764 }
6765 {
6766 //partially blob overwrite under a different csum enablement mode
6767
6768 ObjectStore::Transaction t;
6769 bufferlist bl, orig, orig2;
6770 size_t block_size0 = 0x10000;
6771 size_t block_size = 9000;
6772 size_t block_size2 = 5000;
6773 bl.append(std::string(block_size0, 'a'));
6774 t.remove(cid, hoid);
6775 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
6776 t.write(cid, hoid, 0, bl.length(), bl);
6777 cerr << "Remove then create" << std::endl;
6778 r = queue_transaction(store, ch, std::move(t));
6779 ASSERT_EQ(r, 0);
6780
6781 SetVal(g_conf(), "bluestore_csum_type", "none");
6782 g_conf().apply_changes(nullptr);
6783
6784 ObjectStore::Transaction t2;
6785 bl.clear();
6786 bl.append(std::string(block_size, 'b'));
6787 t2.write(cid, hoid, 0, bl.length(), bl);
6788 t2.write(cid, hoid, block_size0, bl.length(), bl);
6789 cerr << "Overwrite with unprotected data" << std::endl;
6790 r = queue_transaction(store, ch, std::move(t2));
6791 ASSERT_EQ(r, 0);
6792
6793 orig = bl;
6794 orig2 = bl;
6795 orig.append( std::string(block_size0 - block_size, 'a'));
6796
6797 bufferlist in;
6798 r = store->read(ch, hoid, 0, block_size0, in);
6799 ASSERT_EQ((int)block_size0, r);
6800 ASSERT_TRUE(bl_eq(orig, in));
6801
6802 r = store->read(ch, hoid, block_size0, block_size, in);
6803 ASSERT_EQ((int)block_size, r);
6804 ASSERT_TRUE(bl_eq(orig2, in));
6805
6806 SetVal(g_conf(), "bluestore_csum_type", "crc32c");
6807 g_conf().apply_changes(nullptr);
6808
6809 ObjectStore::Transaction t3;
6810 bl.clear();
6811 bl.append(std::string(block_size2, 'c'));
6812 t3.write(cid, hoid, block_size0, bl.length(), bl);
6813 cerr << "Overwrite with protected data" << std::endl;
6814 r = queue_transaction(store, ch, std::move(t3));
6815 ASSERT_EQ(r, 0);
6816
6817 in.clear();
6818 orig = bl;
6819 orig.append( std::string(block_size - block_size2, 'b'));
6820 r = store->read(ch, hoid, block_size0, block_size, in);
6821 ASSERT_EQ((int)block_size, r);
6822 ASSERT_TRUE(bl_eq(orig, in));
6823 }
6824
6825 {
6826 ObjectStore::Transaction t;
6827 t.remove(cid, hoid);
6828 t.remove_collection(cid);
6829 cerr << "Cleaning" << std::endl;
6830 r = queue_transaction(store, ch, std::move(t));
6831 ASSERT_EQ(r, 0);
6832 }
6833 }
6834 #endif
6835
6836 INSTANTIATE_TEST_SUITE_P(
6837 ObjectStore,
6838 StoreTest,
6839 ::testing::Values(
6840 "memstore",
6841 #if defined(WITH_BLUESTORE)
6842 "bluestore",
6843 #endif
6844 "kstore"));
6845
6846 // Note: instantiate all stores to preserve store numbering order only
6847 INSTANTIATE_TEST_SUITE_P(
6848 ObjectStore,
6849 StoreTestSpecificAUSize,
6850 ::testing::Values(
6851 "memstore",
6852 #if defined(WITH_BLUESTORE)
6853 "bluestore",
6854 #endif
6855 "kstore"));
6856
6857 // Note: instantiate all stores to preserve store numbering order only
6858 INSTANTIATE_TEST_SUITE_P(
6859 ObjectStore,
6860 StoreTestOmapUpgrade,
6861 ::testing::Values(
6862 "memstore",
6863 #if defined(WITH_BLUESTORE)
6864 "bluestore",
6865 #endif
6866 "kstore"));
6867
6868 #if defined(WITH_BLUESTORE)
6869 INSTANTIATE_TEST_SUITE_P(
6870 ObjectStore,
6871 StoreTestDeferredSetup,
6872 ::testing::Values(
6873 "bluestore"));
6874 #endif
6875
6876
6877 struct deferred_test_t {
6878 uint32_t bdev_block_size;
6879 uint32_t min_alloc_size;
6880 uint32_t max_blob_size;
6881 uint32_t prefer_deferred_size;
6882 };
6883
6884 void PrintTo(const deferred_test_t& t, ::std::ostream* os)
6885 {
6886 *os << t.bdev_block_size << "/" << t.min_alloc_size << "/"
6887 << t.max_blob_size << "/" << t.prefer_deferred_size;
6888 }
6889
6890 class DeferredWriteTest : public StoreTestFixture,
6891 public ::testing::WithParamInterface<deferred_test_t> {
6892 public:
6893 DeferredWriteTest()
6894 : StoreTestFixture("bluestore")
6895 {}
6896 void SetUp() override {
6897 //do nothing
6898 }
6899 protected:
6900 void DeferredSetup() {
6901 StoreTestFixture::SetUp();
6902 }
6903 public:
6904 std::vector<uint32_t> offsets = {0, 3000, 4096, 20000, 32768, 65000, 65536, 80000, 128 * 1024};
6905 std::vector<uint32_t> lengths = {1, 1000, 4096, 12000, 32768, 30000, 80000, 128 * 1024};
6906 };
6907
6908 TEST_P(DeferredWriteTest, NewData) {
6909 const bool print = false;
6910 deferred_test_t t = GetParam();
6911 SetVal(g_conf(), "bdev_block_size", stringify(t.bdev_block_size).c_str());
6912 SetVal(g_conf(), "bluestore_min_alloc_size", stringify(t.min_alloc_size).c_str());
6913 SetVal(g_conf(), "bluestore_max_blob_size", stringify(t.max_blob_size).c_str());
6914 SetVal(g_conf(), "bluestore_prefer_deferred_size", stringify(t.prefer_deferred_size).c_str());
6915 g_conf().apply_changes(nullptr);
6916 DeferredSetup();
6917
6918 int r;
6919 coll_t cid;
6920 const PerfCounters* logger = store->get_perf_counters();
6921 ObjectStore::CollectionHandle ch = store->create_new_collection(cid);
6922 {
6923 ObjectStore::Transaction t;
6924 t.create_collection(cid, 0);
6925 r = queue_transaction(store, ch, std::move(t));
6926 ASSERT_EQ(r, 0);
6927 }
6928 {
6929 for (auto offset:offsets) {
6930 for (auto length:lengths) {
6931 std::string hname = fmt::format("test-{}-{}", offset, length);
6932 ghobject_t hoid(hobject_t(hname, "", CEPH_NOSNAP, 0, -1, ""));
6933 {
6934 ObjectStore::Transaction t;
6935 t.touch(cid, hoid);
6936 r = queue_transaction(store, ch, std::move(t));
6937 ASSERT_EQ(r, 0);
6938 }
6939 if (print)
6940 std::cout << hname << std::endl;
6941
6942 auto w_new = logger->get(l_bluestore_write_new);
6943 auto w_big_deferred = logger->get(l_bluestore_write_big_deferred);
6944 auto i_deferred_w = logger->get(l_bluestore_issued_deferred_writes);
6945 {
6946 ObjectStore::Transaction t;
6947 bufferlist bl;
6948 bl.append(std::string(length, 'x'));
6949 t.write(cid, hoid, offset, bl.length(), bl,
6950 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
6951 r = queue_transaction(store, ch, std::move(t));
6952 ASSERT_EQ(r, 0);
6953 }
6954 uint32_t first_db = offset / t.bdev_block_size;
6955 uint32_t last_db = (offset + length - 1) / t.bdev_block_size;
6956
6957 uint32_t write_size = (last_db - first_db + 1) * t.bdev_block_size;
6958 if (write_size < t.prefer_deferred_size) {
6959 // expect no direct writes
6960 ASSERT_EQ(w_new , logger->get(l_bluestore_write_new));
6961 } else {
6962 // expect no deferred
6963 ASSERT_EQ(w_big_deferred , logger->get(l_bluestore_write_big_deferred));
6964 ASSERT_EQ(i_deferred_w , logger->get(l_bluestore_issued_deferred_writes));
6965 }
6966 }
6967 }
6968 }
6969 }
6970
6971 #if defined(WITH_BLUESTORE)
6972 INSTANTIATE_TEST_SUITE_P(
6973 BlueStore,
6974 DeferredWriteTest,
6975 ::testing::Values(
6976 // bdev alloc blob deferred
6977 deferred_test_t{4 * 1024, 4 * 1024, 16 * 1024, 32 * 1024},
6978 deferred_test_t{4 * 1024, 16 * 1024, 64 * 1024, 64 * 1024},
6979 deferred_test_t{4 * 1024, 64 * 1024, 64 * 1024, 4 * 1024},
6980 deferred_test_t{4 * 1024, 4 * 1024, 64 * 1024, 0 * 1024},
6981 deferred_test_t{4 * 1024, 16 * 1024, 32 * 1024, 32 * 1024},
6982 deferred_test_t{4 * 1024, 16 * 1024, 64 * 1024, 128 * 1024}
6983 ));
6984 #endif
6985
6986 void doMany4KWritesTest(ObjectStore* store,
6987 unsigned max_objects,
6988 unsigned max_ops,
6989 unsigned max_object_size,
6990 unsigned max_write_size,
6991 unsigned write_alignment)
6992 {
6993 MixedGenerator gen(555);
6994 gen_type rng(time(NULL));
6995 coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
6996 store_statfs_t res_stat;
6997
6998 SyntheticWorkloadState test_obj(store,
6999 &gen,
7000 &rng,
7001 cid,
7002 max_object_size,
7003 max_write_size,
7004 write_alignment);
7005 test_obj.init();
7006 for (unsigned i = 0; i < max_objects; ++i) {
7007 if (!(i % 500)) cerr << "seeding object " << i << std::endl;
7008 test_obj.touch();
7009 }
7010 for (unsigned i = 0; i < max_ops; ++i) {
7011 if (!(i % 200)) {
7012 cerr << "Op " << i << std::endl;
7013 test_obj.print_internal_state();
7014 }
7015 test_obj.write();
7016 }
7017 test_obj.wait_for_done();
7018 test_obj.statfs(res_stat);
7019 if (!(res_stat.data_stored <= max_object_size) ||
7020 !(res_stat.allocated <= max_object_size)) {
7021 // this will provide more insight on the mismatch and
7022 // helps to avoid any races during stats collection
7023 test_obj.fsck(false);
7024 // retrieving stats once again and assert if still broken
7025 test_obj.statfs(res_stat);
7026 ASSERT_LE(res_stat.data_stored, max_object_size);
7027 ASSERT_LE(res_stat.allocated, max_object_size);
7028 }
7029 test_obj.shutdown();
7030 }
7031
7032 TEST_P(StoreTestSpecificAUSize, Many4KWritesTest) {
7033 if (string(GetParam()) != "bluestore")
7034 return;
7035 if (smr) {
7036 cout << "SKIP: no deferred; assertions around res_stat.allocated don't apply"
7037 << std::endl;
7038 return;
7039 }
7040
7041 StartDeferred(0x10000);
7042
7043 const unsigned max_object = 4*1024*1024;
7044 doMany4KWritesTest(store.get(), 1, 1000, max_object, 4*1024, 0);
7045 }
7046
7047 TEST_P(StoreTestSpecificAUSize, Many4KWritesNoCSumTest) {
7048 if (string(GetParam()) != "bluestore")
7049 return;
7050 if (smr) {
7051 cout << "SKIP: no deferred; assertions around res_stat.allocated don't apply"
7052 << std::endl;
7053 return;
7054 }
7055 StartDeferred(0x10000);
7056 SetVal(g_conf(), "bluestore_csum_type", "none");
7057 g_ceph_context->_conf.apply_changes(nullptr);
7058 const unsigned max_object = 4*1024*1024;
7059
7060 doMany4KWritesTest(store.get(), 1, 1000, max_object, 4*1024, 0 );
7061 }
7062
7063 TEST_P(StoreTestSpecificAUSize, TooManyBlobsTest) {
7064 if (string(GetParam()) != "bluestore")
7065 return;
7066 if (smr) {
7067 cout << "SKIP: no deferred; assertions around res_stat.allocated don't apply"
7068 << std::endl;
7069 return;
7070 }
7071 StartDeferred(0x10000);
7072 const unsigned max_object = 4*1024*1024;
7073 doMany4KWritesTest(store.get(), 1, 1000, max_object, 4*1024, 0);
7074 }
7075
7076 #if defined(WITH_BLUESTORE)
7077 void get_mempool_stats(uint64_t* total_bytes, uint64_t* total_items)
7078 {
7079 uint64_t meta_allocated = mempool::bluestore_cache_meta::allocated_bytes();
7080 uint64_t onode_allocated = mempool::bluestore_cache_onode::allocated_bytes();
7081 uint64_t other_allocated = mempool::bluestore_cache_other::allocated_bytes();
7082
7083 uint64_t meta_items = mempool::bluestore_cache_meta::allocated_items();
7084 uint64_t onode_items = mempool::bluestore_cache_onode::allocated_items();
7085 uint64_t other_items = mempool::bluestore_cache_other::allocated_items();
7086 cout << "meta(" << meta_allocated << "/" << meta_items
7087 << ") onode(" << onode_allocated << "/" << onode_items
7088 << ") other(" << other_allocated << "/" << other_items
7089 << ")" << std::endl;
7090 *total_bytes = meta_allocated + onode_allocated + other_allocated;
7091 *total_items = onode_items;
7092 }
7093
7094 TEST_P(StoreTestSpecificAUSize, OnodeSizeTracking) {
7095
7096 if (string(GetParam()) != "bluestore")
7097 return;
7098
7099 size_t block_size = 4096;
7100 StartDeferred(block_size);
7101 SetVal(g_conf(), "bluestore_compression_mode", "none");
7102 SetVal(g_conf(), "bluestore_csum_type", "none");
7103 SetVal(g_conf(), "bluestore_cache_size_hdd", "400000000");
7104 SetVal(g_conf(), "bluestore_cache_size_ssd", "400000000");
7105 g_conf().apply_changes(nullptr);
7106
7107 int r;
7108 coll_t cid;
7109 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
7110 size_t obj_size = 4 * 1024 * 1024;
7111 uint64_t total_bytes_prev;
7112 uint64_t total_bytes, total_bytes2;
7113 uint64_t total_onodes;
7114 get_mempool_stats(&total_bytes, &total_onodes);
7115 total_bytes_prev = total_bytes;
7116 // 5u for onode_cache_shards vector
7117 ASSERT_EQ(total_onodes, 5u);
7118 ASSERT_EQ(total_bytes, 40u);
7119
7120 auto ch = store->create_new_collection(cid);
7121 {
7122 ObjectStore::Transaction t;
7123 t.create_collection(cid, 0);
7124 r = queue_transaction(store, ch, std::move(t));
7125 ASSERT_EQ(r, 0);
7126 }
7127 {
7128 ObjectStore::Transaction t;
7129 bufferlist bl, orig, orig2;
7130
7131 bl.append(std::string(obj_size, 'a'));
7132 t.write(cid, hoid, 0, bl.length(), bl);
7133 r = queue_transaction(store, ch, std::move(t));
7134 ASSERT_EQ(r, 0);
7135 }
7136 get_mempool_stats(&total_bytes, &total_onodes);
7137 ASSERT_GT(total_bytes - total_bytes_prev, 0u);
7138 ASSERT_EQ(total_onodes, 6u);
7139
7140 {
7141 ObjectStore::Transaction t;
7142 t.truncate(cid, hoid, 0);
7143 r = queue_transaction(store, ch, std::move(t));
7144 ASSERT_EQ(r, 0);
7145 }
7146
7147 for(size_t i = 0; i < 1; ++i) {
7148 bufferlist bl;
7149 bl.append(std::string(block_size * (i+1), 'a'));
7150 for( size_t j = 0; j < obj_size; j+= bl.length()) {
7151 ObjectStore::Transaction t;
7152 t.write(cid, hoid, j, bl.length(), bl);
7153 r = queue_transaction(store, ch, std::move(t));
7154 ASSERT_EQ(r, 0);
7155 }
7156 get_mempool_stats(&total_bytes2, &total_onodes);
7157 ASSERT_NE(total_bytes2, 0u);
7158 ASSERT_EQ(total_onodes, 6u);
7159 }
7160 {
7161 cout <<" mempool dump:\n";
7162 JSONFormatter f(true);
7163 f.open_object_section("transaction");
7164 mempool::dump(&f);
7165 f.close_section();
7166 f.flush(cout);
7167 cout << std::endl;
7168 }
7169 {
7170 bufferlist bl;
7171 for (size_t i = 0; i < obj_size; i += 0x1000) {
7172 store->read(ch, hoid, i, 0x1000, bl);
7173 }
7174 }
7175 get_mempool_stats(&total_bytes, &total_onodes);
7176 ASSERT_NE(total_bytes, 0u);
7177 ASSERT_EQ(total_onodes, 6u);
7178
7179 {
7180 cout <<" mempool dump:\n";
7181 JSONFormatter f(true);
7182 f.open_object_section("transaction");
7183 mempool::dump(&f);
7184 f.close_section();
7185 f.flush(cout);
7186 cout << std::endl;
7187 }
7188 {
7189 ObjectStore::Transaction t;
7190 t.remove(cid, hoid);
7191 t.remove_collection(cid);
7192 cerr << "Cleaning" << std::endl;
7193 r = queue_transaction(store, ch, std::move(t));
7194 ASSERT_EQ(r, 0);
7195 }
7196 }
7197
7198 TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwrite) {
7199
7200 if (string(GetParam()) != "bluestore")
7201 return;
7202
7203 size_t block_size = 4096;
7204 StartDeferred(block_size);
7205 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
7206 g_conf().apply_changes(nullptr);
7207
7208 int r;
7209 coll_t cid;
7210 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
7211
7212 const PerfCounters* logger = store->get_perf_counters();
7213
7214 auto ch = store->create_new_collection(cid);
7215 {
7216 ObjectStore::Transaction t;
7217 t.create_collection(cid, 0);
7218 r = queue_transaction(store, ch, std::move(t));
7219 ASSERT_EQ(r, 0);
7220 }
7221 {
7222 ObjectStore::Transaction t;
7223 bufferlist bl;
7224
7225 bl.append(std::string(block_size * 2, 'a'));
7226 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
7227 r = queue_transaction(store, ch, std::move(t));
7228 ASSERT_EQ(r, 0);
7229 }
7230 {
7231 // overwrite at the beginning
7232 ObjectStore::Transaction t;
7233 bufferlist bl;
7234
7235 bl.append(std::string(block_size, 'b'));
7236 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
7237 r = queue_transaction(store, ch, std::move(t));
7238 ASSERT_EQ(r, 0);
7239 }
7240 {
7241 // append
7242 ObjectStore::Transaction t;
7243 bufferlist bl;
7244
7245 bl.append(std::string(block_size * 2, 'c'));
7246 t.write(cid, hoid, block_size * 2, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
7247 r = queue_transaction(store, ch, std::move(t));
7248 ASSERT_EQ(r, 0);
7249 }
7250 {
7251 // append with a gap
7252 ObjectStore::Transaction t;
7253 bufferlist bl;
7254
7255 bl.append(std::string(block_size * 2, 'd'));
7256 t.write(cid, hoid, block_size * 5, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
7257 r = queue_transaction(store, ch, std::move(t));
7258 ASSERT_EQ(r, 0);
7259 }
7260 {
7261 // We need to issue a read to trigger cache stat update that refresh
7262 // perf counters. additionally we need to wait some time for mempool
7263 // thread to update stats.
7264 sleep(1);
7265 bufferlist bl, expected;
7266 r = store->read(ch, hoid, 0, block_size, bl);
7267 ASSERT_EQ(r, (int)block_size);
7268 expected.append(string(block_size, 'b'));
7269 ASSERT_TRUE(bl_eq(expected, bl));
7270 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
7271 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
7272 }
7273 {
7274 // overwrite at end
7275 ObjectStore::Transaction t;
7276 bufferlist bl;
7277
7278 bl.append(std::string(block_size * 2, 'e'));
7279
7280 // Currently we are unable to reuse blob when overwriting in a single step
7281 t.write(cid, hoid, block_size * 6, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
7282 r = queue_transaction(store, ch, std::move(t));
7283 ASSERT_EQ(r, 0);
7284 }
7285 {
7286 // We need to issue a read to trigger cache stat update that refresh
7287 // perf counters. additionally we need to wait some time for mempool
7288 // thread to update stats.
7289 sleep(1);
7290 bufferlist bl, expected;
7291 r = store->read(ch, hoid, 0, block_size, bl);
7292 ASSERT_EQ(r, (int)block_size);
7293 expected.append(string(block_size, 'b'));
7294 ASSERT_TRUE(bl_eq(expected, bl));
7295 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
7296 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
7297 }
7298 {
7299 // fill the gap
7300 ObjectStore::Transaction t;
7301 bufferlist bl;
7302
7303 bl.append(std::string(block_size, 'f'));
7304
7305 t.write(cid, hoid, block_size * 4, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
7306 r = queue_transaction(store, ch, std::move(t));
7307 ASSERT_EQ(r, 0);
7308 }
7309 {
7310 // we need to wait some time for mempool
7311 // thread to update stats to be able to check blob/extent numbers from
7312 // perf counters.
7313 sleep(1);
7314
7315 bufferlist bl, expected;
7316 r = store->read(ch, hoid, 0, block_size, bl);
7317 ASSERT_EQ(r, (int)block_size);
7318 expected.append(string(block_size, 'b'));
7319 ASSERT_TRUE(bl_eq(expected, bl));
7320
7321 bl.clear();
7322 expected.clear();
7323 r = store->read(ch, hoid, block_size, block_size, bl);
7324 ASSERT_EQ(r, (int)block_size);
7325 expected.append(string(block_size, 'a'));
7326 ASSERT_TRUE(bl_eq(expected, bl));
7327
7328 bl.clear();
7329 expected.clear();
7330 r = store->read(ch, hoid, block_size * 2, block_size * 2, bl);
7331 ASSERT_EQ(r, (int)block_size * 2);
7332 expected.append(string(block_size * 2, 'c'));
7333 ASSERT_TRUE(bl_eq(expected, bl));
7334
7335 bl.clear();
7336 expected.clear();
7337 r = store->read(ch, hoid, block_size * 4, block_size, bl);
7338 ASSERT_EQ(r, (int)block_size);
7339 expected.append(string(block_size, 'f'));
7340 ASSERT_TRUE(bl_eq(expected, bl));
7341
7342 bl.clear();
7343 expected.clear();
7344 r = store->read(ch, hoid, block_size * 5, block_size, bl);
7345 ASSERT_EQ(r, (int)block_size);
7346 expected.append(string(block_size, 'd'));
7347 ASSERT_TRUE(bl_eq(expected, bl));
7348
7349 bl.clear();
7350 expected.clear();
7351 r = store->read(ch, hoid, block_size * 5, block_size * 3, bl);
7352 ASSERT_EQ(r, (int)block_size * 3);
7353 expected.append(string(block_size, 'd'));
7354 expected.append(string(block_size * 2, 'e'));
7355 ASSERT_TRUE(bl_eq(expected, bl));
7356 }
7357 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
7358 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
7359
7360
7361 {
7362 ObjectStore::Transaction t;
7363 t.remove(cid, hoid);
7364 t.remove_collection(cid);
7365 cerr << "Cleaning" << std::endl;
7366 r = queue_transaction(store, ch, std::move(t));
7367 ASSERT_EQ(r, 0);
7368 }
7369 }
7370
7371 TEST_P(StoreTestSpecificAUSize, ZeroBlockDetectionSmallAppend) {
7372 CephContext *cct = (new CephContext(CEPH_ENTITY_TYPE_CLIENT))->get();
7373 if (string(GetParam()) != "bluestore" || !cct->_conf->bluestore_zero_block_detection) {
7374 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7375 }
7376
7377 size_t block_size = 65536;
7378 StartDeferred(block_size);
7379
7380 int r;
7381 coll_t cid;
7382 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
7383
7384 const PerfCounters* logger = store->get_perf_counters();
7385
7386 auto ch = store->create_new_collection(cid);
7387 {
7388 ObjectStore::Transaction t;
7389 t.create_collection(cid, 0);
7390 r = queue_transaction(store, ch, std::move(t));
7391 ASSERT_EQ(r, 0);
7392 }
7393 {
7394 // [1] append zeros
7395 ObjectStore::Transaction t;
7396 bufferlist bl;
7397
7398 bl.append_zero(4096);
7399
7400 t.write(cid, hoid, 0, bl.length(), bl);
7401 r = queue_transaction(store, ch, std::move(t));
7402 ASSERT_EQ(r, 0);
7403 ASSERT_EQ(logger->get(l_bluestore_write_small), 1u);
7404 ASSERT_EQ(logger->get(l_bluestore_write_small_bytes), 4096u);
7405 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped), 1u);
7406 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped_bytes), 4096u);
7407
7408 bufferlist in;
7409 r = store->read(ch, hoid, 0, 0x4000, in);
7410 ASSERT_EQ(4096, r);
7411 ASSERT_TRUE(in.is_zero());
7412 }
7413
7414 {
7415 // [2] append non-zeros
7416 ObjectStore::Transaction t;
7417 bufferlist bl;
7418
7419 bl.append(std::string(4096, 'c'));
7420
7421 t.write(cid, hoid, 4096, bl.length(), bl);
7422 r = queue_transaction(store, ch, std::move(t));
7423 ASSERT_EQ(r, 0);
7424 ASSERT_EQ(logger->get(l_bluestore_write_small), 2u);
7425 ASSERT_EQ(logger->get(l_bluestore_write_small_bytes), 4096u*2);
7426 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped), 1u);
7427 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped_bytes), 4096u);
7428
7429 bufferlist in, _exp;
7430 r = store->read(ch, hoid, 0, 0x4000, in);
7431 ASSERT_EQ(4096 * 2, r);
7432 _exp.append_zero(4096);
7433 _exp.append(bl);
7434 ASSERT_TRUE(bl_eq(_exp, in));
7435 }
7436
7437 {
7438 ObjectStore::Transaction t;
7439 t.remove(cid, hoid);
7440 t.remove_collection(cid);
7441 cerr << "Cleaning" << std::endl;
7442 r = queue_transaction(store, ch, std::move(t));
7443 ASSERT_EQ(r, 0);
7444 }
7445 }
7446
7447 TEST_P(StoreTestSpecificAUSize, ZeroBlockDetectionSmallOverwrite) {
7448 CephContext *cct = (new CephContext(CEPH_ENTITY_TYPE_CLIENT))->get();
7449 if (string(GetParam()) != "bluestore" || !cct->_conf->bluestore_zero_block_detection) {
7450 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7451 }
7452 if (smr) {
7453 GTEST_SKIP() << "smr, skipping";
7454 }
7455
7456 size_t block_size = 65536;
7457 StartDeferred(block_size);
7458
7459 int r;
7460 coll_t cid;
7461 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
7462
7463 const PerfCounters* logger = store->get_perf_counters();
7464
7465 auto ch = store->create_new_collection(cid);
7466 {
7467 ObjectStore::Transaction t;
7468 t.create_collection(cid, 0);
7469 r = queue_transaction(store, ch, std::move(t));
7470 ASSERT_EQ(r, 0);
7471 }
7472
7473 {
7474 // {setting up the scenario} append non-zeros
7475 ObjectStore::Transaction t;
7476 bufferlist bl;
7477
7478 bl.append(std::string(4096, 'c'));
7479
7480 t.write(cid, hoid, 0, bl.length(), bl);
7481 r = queue_transaction(store, ch, std::move(t));
7482 ASSERT_EQ(r, 0);
7483 ASSERT_EQ(logger->get(l_bluestore_write_small), 1u);
7484 ASSERT_EQ(logger->get(l_bluestore_write_small_bytes), 4096u);
7485 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped), 0u);
7486 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped_bytes), 0u);
7487
7488 bufferlist in, _exp;
7489 r = store->read(ch, hoid, 0, 0x4000, in);
7490 ASSERT_EQ(4096, r);
7491 _exp.append(bl);
7492 ASSERT_TRUE(bl_eq(_exp, in));
7493 }
7494
7495 {
7496 // [1] overwrite non-zeros with zeros
7497 ObjectStore::Transaction t;
7498 bufferlist bl;
7499
7500 bl.append_zero(4096);
7501
7502 t.write(cid, hoid, 0, bl.length(), bl);
7503 r = queue_transaction(store, ch, std::move(t));
7504 ASSERT_EQ(r, 0);
7505 ASSERT_EQ(logger->get(l_bluestore_write_small), 2u);
7506 ASSERT_EQ(logger->get(l_bluestore_write_small_bytes), 4096u*2);
7507 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped), 0u);
7508 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped_bytes), 0u);
7509
7510 bufferlist in;
7511 r = store->read(ch, hoid, 0, 0x4000, in);
7512 ASSERT_EQ(4096, r);
7513 ASSERT_TRUE(in.is_zero());
7514 }
7515
7516 {
7517 // [2] overwrite zeros with non-zeros
7518 ObjectStore::Transaction t;
7519 bufferlist bl;
7520
7521 bl.append(std::string(4096, 'c'));
7522
7523 t.write(cid, hoid, 0, bl.length(), bl);
7524 r = queue_transaction(store, ch, std::move(t));
7525 ASSERT_EQ(r, 0);
7526 ASSERT_EQ(logger->get(l_bluestore_write_small), 3u);
7527 ASSERT_EQ(logger->get(l_bluestore_write_small_bytes), 4096u*3);
7528 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped), 0u);
7529 ASSERT_EQ(logger->get(l_bluestore_write_small_skipped_bytes), 0u);
7530
7531 bufferlist in, _exp;
7532 r = store->read(ch, hoid, 0, 0x4000, in);
7533 ASSERT_EQ(4096, r);
7534 _exp.append(bl);
7535 ASSERT_TRUE(bl_eq(_exp, in));
7536 }
7537
7538 {
7539 ObjectStore::Transaction t;
7540 t.remove(cid, hoid);
7541 t.remove_collection(cid);
7542 cerr << "Cleaning" << std::endl;
7543 r = queue_transaction(store, ch, std::move(t));
7544 ASSERT_EQ(r, 0);
7545 }
7546 }
7547
7548 TEST_P(StoreTestSpecificAUSize, ZeroBlockDetectionBigAppend) {
7549 CephContext *cct = (new CephContext(CEPH_ENTITY_TYPE_CLIENT))->get();
7550 if (string(GetParam()) != "bluestore" || !cct->_conf->bluestore_zero_block_detection) {
7551 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7552 }
7553
7554 size_t block_size = 4096;
7555 StartDeferred(block_size);
7556
7557 int r;
7558 coll_t cid;
7559 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
7560
7561 const PerfCounters* logger = store->get_perf_counters();
7562
7563 auto ch = store->create_new_collection(cid);
7564 {
7565 ObjectStore::Transaction t;
7566 t.create_collection(cid, 0);
7567 r = queue_transaction(store, ch, std::move(t));
7568 ASSERT_EQ(r, 0);
7569 }
7570
7571 {
7572 // [1] append zeros
7573 ObjectStore::Transaction t;
7574 bufferlist bl;
7575
7576 bl.append_zero(block_size * 2);
7577
7578 t.write(cid, hoid, 0, bl.length(), bl);
7579 r = queue_transaction(store, ch, std::move(t));
7580 ASSERT_EQ(r, 0);
7581 ASSERT_EQ(logger->get(l_bluestore_write_big), 1u);
7582 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), 4096u*2);
7583 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 0u);
7584 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_blobs), 1u);
7585 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_bytes), 4096u*2);
7586
7587 bufferlist in;
7588 r = store->read(ch, hoid, 0, block_size * 8, in);
7589 ASSERT_EQ(block_size * 2, r);
7590 ASSERT_TRUE(in.is_zero());
7591 }
7592
7593 {
7594 // [2] append non-zeros
7595 ObjectStore::Transaction t;
7596 bufferlist bl;
7597
7598 bl.append(std::string(block_size * 2, 'c'));
7599
7600 t.write(cid, hoid, block_size * 2, bl.length(), bl);
7601 r = queue_transaction(store, ch, std::move(t));
7602 ASSERT_EQ(r, 0);
7603 ASSERT_EQ(logger->get(l_bluestore_write_big), 2u);
7604 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), 4096u*4);
7605 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 1u);
7606 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_blobs), 1u);
7607 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_bytes), 4096u*2);
7608
7609 bufferlist in, _exp;
7610 r = store->read(ch, hoid, 0, block_size * 8, in);
7611 ASSERT_EQ(block_size * 4, r);
7612 _exp.append_zero(block_size * 2);
7613 _exp.append(bl);
7614 ASSERT_TRUE(bl_eq(_exp, in));
7615 }
7616
7617 {
7618 ObjectStore::Transaction t;
7619 t.remove(cid, hoid);
7620 t.remove_collection(cid);
7621 cerr << "Cleaning" << std::endl;
7622 r = queue_transaction(store, ch, std::move(t));
7623 ASSERT_EQ(r, 0);
7624 }
7625 }
7626
7627 TEST_P(StoreTestSpecificAUSize, ZeroBlockDetectionBigOverwrite) {
7628 CephContext *cct = (new CephContext(CEPH_ENTITY_TYPE_CLIENT))->get();
7629 if (string(GetParam()) != "bluestore" || !cct->_conf->bluestore_zero_block_detection) {
7630 GTEST_SKIP() << "not bluestore or bluestore_zero_block_detection=false, skipping";
7631 }
7632 if (smr) {
7633 GTEST_SKIP() << "smr, skipping";
7634 }
7635
7636 size_t block_size = 4096;
7637 StartDeferred(block_size);
7638
7639 int r;
7640 coll_t cid;
7641 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
7642
7643 const PerfCounters* logger = store->get_perf_counters();
7644
7645 auto ch = store->create_new_collection(cid);
7646 {
7647 ObjectStore::Transaction t;
7648 t.create_collection(cid, 0);
7649 r = queue_transaction(store, ch, std::move(t));
7650 ASSERT_EQ(r, 0);
7651 }
7652
7653 {
7654 // {setting up the scenario} append non-zeros
7655 ObjectStore::Transaction t;
7656 bufferlist bl;
7657
7658 bl.append(std::string(block_size * 2, 'c'));
7659
7660 t.write(cid, hoid, 0, bl.length(), bl);
7661 r = queue_transaction(store, ch, std::move(t));
7662 ASSERT_EQ(r, 0);
7663 ASSERT_EQ(logger->get(l_bluestore_write_big), 1u);
7664 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), 4096u*2);
7665 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 1u);
7666 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_blobs), 0u);
7667 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_bytes), 0u);
7668
7669 bufferlist in, _exp;
7670 r = store->read(ch, hoid, 0, block_size * 8, in);
7671 ASSERT_EQ(block_size * 2, r);
7672 _exp.append(bl);
7673 ASSERT_TRUE(bl_eq(_exp, in));
7674 }
7675
7676 {
7677 // [1] overwrite non-zeros with zeros
7678 ObjectStore::Transaction t;
7679 bufferlist bl;
7680
7681 bl.append_zero(block_size * 2);
7682
7683 t.write(cid, hoid, 0, bl.length(), bl);
7684 r = queue_transaction(store, ch, std::move(t));
7685 ASSERT_EQ(r, 0);
7686 ASSERT_EQ(logger->get(l_bluestore_write_big), 2u);
7687 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), 4096u*4);
7688 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 1u);
7689 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_blobs), 1u);
7690 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_bytes), 4096u*2);
7691
7692 bufferlist in;
7693 r = store->read(ch, hoid, 0, block_size * 8, in);
7694 ASSERT_EQ(block_size * 2, r);
7695 ASSERT_TRUE(in.is_zero());
7696 }
7697
7698 {
7699 // [2] overwrite zeros with non-zeros
7700 ObjectStore::Transaction t;
7701 bufferlist bl;
7702
7703 bl.append(std::string(block_size * 2, 'c'));
7704
7705 t.write(cid, hoid, 0, bl.length(), bl);
7706 r = queue_transaction(store, ch, std::move(t));
7707 ASSERT_EQ(r, 0);
7708 ASSERT_EQ(logger->get(l_bluestore_write_big), 3u);
7709 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), 4096u*6);
7710 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 2u);
7711 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_blobs), 1u);
7712 ASSERT_EQ(logger->get(l_bluestore_write_big_skipped_bytes), 4096u*2);
7713
7714 bufferlist in, _exp;
7715 r = store->read(ch, hoid, 0, block_size * 8, in);
7716 ASSERT_EQ(block_size * 2, r);
7717 _exp.append(bl);
7718 ASSERT_TRUE(bl_eq(_exp, in));
7719 }
7720
7721 {
7722 ObjectStore::Transaction t;
7723 t.remove(cid, hoid);
7724 t.remove_collection(cid);
7725 cerr << "Cleaning" << std::endl;
7726 r = queue_transaction(store, ch, std::move(t));
7727 ASSERT_EQ(r, 0);
7728 }
7729 }
7730
7731 TEST_P(StoreTestSpecificAUSize, DeferredOnBigOverwrite) {
7732
7733 if (string(GetParam()) != "bluestore")
7734 return;
7735 if (smr) {
7736 cout << "SKIP: no deferred" << std::endl;
7737 return;
7738 }
7739
7740 size_t block_size = 4096;
7741 StartDeferred(block_size);
7742 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
7743 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
7744
7745 g_conf().apply_changes(nullptr);
7746
7747 int r;
7748 coll_t cid;
7749 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
7750 ghobject_t hoid2(hobject_t("test2", "", CEPH_NOSNAP, 0, -1, ""));
7751
7752 PerfCounters* logger = const_cast<PerfCounters*>(store->get_perf_counters());
7753
7754 auto ch = store->create_new_collection(cid);
7755 {
7756 ObjectStore::Transaction t;
7757 t.create_collection(cid, 0);
7758 r = queue_transaction(store, ch, std::move(t));
7759 ASSERT_EQ(r, 0);
7760 }
7761 {
7762 ObjectStore::Transaction t;
7763 bufferlist bl, bl2;
7764
7765 bl.append(std::string(block_size * 2, 'c'));
7766 bl2.append(std::string(block_size * 3, 'd'));
7767
7768 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7769 t.set_alloc_hint(cid, hoid2, block_size * 4, block_size * 4,
7770 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ);
7771 t.write(cid, hoid2, 0, bl2.length(), bl2, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7772 r = queue_transaction(store, ch, std::move(t));
7773 ASSERT_EQ(r, 0);
7774 }
7775 ASSERT_EQ(logger->get(l_bluestore_write_big), 2u);
7776 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 0u);
7777
7778 {
7779 struct store_statfs_t statfs;
7780 int r = store->statfs(&statfs);
7781 ASSERT_EQ(r, 0);
7782 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 5);
7783 ASSERT_LE(statfs.allocated, (unsigned)block_size * 5);
7784 }
7785
7786 // overwrite at the beginning, 4K alignment
7787 {
7788 ObjectStore::Transaction t;
7789 bufferlist bl;
7790
7791 bl.append(std::string(block_size, 'b'));
7792 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7793 r = queue_transaction(store, ch, std::move(t));
7794 ASSERT_EQ(r, 0);
7795 }
7796 ASSERT_EQ(logger->get(l_bluestore_write_big), 3u);
7797 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 1u);
7798
7799 {
7800 bufferlist bl, expected;
7801 r = store->read(ch, hoid, 0, block_size, bl);
7802 ASSERT_EQ(r, (int)block_size);
7803 expected.append(string(block_size, 'b'));
7804 ASSERT_TRUE(bl_eq(expected, bl));
7805 }
7806 {
7807 bufferlist bl, expected;
7808 r = store->read(ch, hoid, block_size, block_size, bl);
7809 ASSERT_EQ(r, (int)block_size);
7810 expected.append(string(block_size, 'c'));
7811 ASSERT_TRUE(bl_eq(expected, bl));
7812 }
7813
7814 // overwrite at the end, 4K alignment
7815 {
7816 ObjectStore::Transaction t;
7817 bufferlist bl;
7818
7819 bl.append(std::string(block_size, 'g'));
7820 t.write(cid, hoid, block_size, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7821 r = queue_transaction(store, ch, std::move(t));
7822 ASSERT_EQ(r, 0);
7823 }
7824 ASSERT_EQ(logger->get(l_bluestore_write_big), 4u);
7825 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 2u);
7826
7827 {
7828 bufferlist bl, expected;
7829 r = store->read(ch, hoid, 0, block_size, bl);
7830 ASSERT_EQ(r, (int)block_size);
7831 expected.append(string(block_size, 'b'));
7832 ASSERT_TRUE(bl_eq(expected, bl));
7833 }
7834 {
7835 bufferlist bl, expected;
7836 r = store->read(ch, hoid, block_size, block_size, bl);
7837 ASSERT_EQ(r, (int)block_size);
7838 expected.append(string(block_size, 'g'));
7839 ASSERT_TRUE(bl_eq(expected, bl));
7840 }
7841
7842 // overwrite at 4K, 12K alignment
7843 {
7844 ObjectStore::Transaction t;
7845 bufferlist bl;
7846
7847 bl.append(std::string(block_size, 'e'));
7848 t.write(cid, hoid2, block_size , bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7849 r = queue_transaction(store, ch, std::move(t));
7850 ASSERT_EQ(r, 0);
7851 }
7852 ASSERT_EQ(logger->get(l_bluestore_write_big), 5u);
7853 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 3u);
7854
7855 // makes sure deferred has been submitted
7856 // and do all the checks again
7857 sleep(g_conf().get_val<double>("bluestore_max_defer_interval") + 2);
7858
7859 ASSERT_EQ(logger->get(l_bluestore_write_big), 5u);
7860 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 3u);
7861
7862 {
7863 bufferlist bl, expected;
7864 r = store->read(ch, hoid, 0, block_size, bl);
7865 ASSERT_EQ(r, (int)block_size);
7866 expected.append(string(block_size, 'b'));
7867 ASSERT_TRUE(bl_eq(expected, bl));
7868 }
7869 {
7870 bufferlist bl, expected;
7871 r = store->read(ch, hoid, block_size, block_size, bl);
7872 ASSERT_EQ(r, (int)block_size);
7873 expected.append(string(block_size, 'g'));
7874 ASSERT_TRUE(bl_eq(expected, bl));
7875 }
7876 {
7877 bufferlist bl, expected;
7878 r = store->read(ch, hoid2, 0, block_size, bl);
7879 ASSERT_EQ(r, (int)block_size);
7880 expected.append(string(block_size, 'd'));
7881 ASSERT_TRUE(bl_eq(expected, bl));
7882 }
7883 {
7884 bufferlist bl, expected;
7885 r = store->read(ch, hoid2, block_size, block_size, bl);
7886 ASSERT_EQ(r, (int)block_size);
7887 expected.append(string(block_size, 'e'));
7888 ASSERT_TRUE(bl_eq(expected, bl));
7889 }
7890 {
7891 bufferlist bl, expected;
7892 r = store->read(ch, hoid2, block_size * 2, block_size, bl);
7893 ASSERT_EQ(r, (int)block_size);
7894 expected.append(string(block_size, 'd'));
7895 ASSERT_TRUE(bl_eq(expected, bl));
7896 }
7897
7898 {
7899 struct store_statfs_t statfs;
7900 int r = store->statfs(&statfs);
7901 ASSERT_EQ(r, 0);
7902 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 5);
7903 ASSERT_LE(statfs.allocated, (unsigned)block_size * 5);
7904 }
7905 ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
7906 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
7907
7908 {
7909 ObjectStore::Transaction t;
7910 t.remove(cid, hoid);
7911 t.remove(cid, hoid2);
7912 r = queue_transaction(store, ch, std::move(t));
7913 ASSERT_EQ(r, 0);
7914 }
7915
7916 {
7917 ObjectStore::Transaction t;
7918 bufferlist bl;
7919 bl.append(std::string(block_size * 2, 'f'));
7920
7921 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7922 r = queue_transaction(store, ch, std::move(t));
7923 ASSERT_EQ(r, 0);
7924 }
7925 ASSERT_EQ(logger->get(l_bluestore_write_big), 6u);
7926 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 3u);
7927
7928 {
7929 ObjectStore::Transaction t;
7930 t.zero(cid, hoid, 0, 100);
7931 r = queue_transaction(store, ch, std::move(t));
7932 ASSERT_EQ(r, 0);
7933 }
7934 {
7935 bufferlist bl, expected;
7936 r = store->read(ch, hoid, 0, 100, bl);
7937 ASSERT_EQ(r, (int)100);
7938 expected.append(string(100, 0));
7939 ASSERT_TRUE(bl_eq(expected, bl));
7940 }
7941 {
7942 bufferlist bl, expected;
7943 r = store->read(ch, hoid, 100, block_size * 2 - 100, bl);
7944 ASSERT_EQ(r, (int)block_size * 2 - 100);
7945 expected.append(string(block_size * 2 - 100, 'f'));
7946 ASSERT_TRUE(bl_eq(expected, bl));
7947 }
7948 sleep(2);
7949 {
7950 struct store_statfs_t statfs;
7951 int r = store->statfs(&statfs);
7952 ASSERT_EQ(r, 0);
7953 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 2 - 100);
7954 ASSERT_LE(statfs.allocated, (unsigned)block_size * 2);
7955 }
7956 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
7957 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
7958
7959 {
7960 ObjectStore::Transaction t;
7961 bufferlist bl;
7962 bl.append(std::string(block_size, 'g'));
7963
7964 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
7965 r = queue_transaction(store, ch, std::move(t));
7966 ASSERT_EQ(r, 0);
7967 }
7968 ASSERT_EQ(logger->get(l_bluestore_write_big), 7u);
7969 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 4u);
7970 {
7971 bufferlist bl, expected;
7972 r = store->read(ch, hoid, 0, block_size, bl);
7973 ASSERT_EQ(r, (int)block_size);
7974 expected.append(string(block_size, 'g'));
7975 ASSERT_TRUE(bl_eq(expected, bl));
7976 }
7977 {
7978 bufferlist bl, expected;
7979 r = store->read(ch, hoid, block_size, block_size, bl);
7980 ASSERT_EQ(r, (int)block_size);
7981 expected.append(string(block_size, 'f'));
7982 ASSERT_TRUE(bl_eq(expected, bl));
7983 }
7984
7985 {
7986 struct store_statfs_t statfs;
7987 int r = store->statfs(&statfs);
7988 ASSERT_EQ(r, 0);
7989 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 2);
7990 ASSERT_LE(statfs.allocated, (unsigned)block_size * 2);
7991 }
7992 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
7993 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
7994
7995 // check whether full overwrite bypass deferred
7996 {
7997 ObjectStore::Transaction t;
7998 bufferlist bl;
7999 bl.append(std::string(block_size * 2, 'h'));
8000
8001 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8002 r = queue_transaction(store, ch, std::move(t));
8003 ASSERT_EQ(r, 0);
8004 }
8005 ASSERT_EQ(logger->get(l_bluestore_write_big), 8u);
8006 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 4u);
8007
8008 {
8009 bufferlist bl, expected;
8010 r = store->read(ch, hoid, 0, block_size * 2, bl);
8011 ASSERT_EQ(r, (int)block_size * 2);
8012 expected.append(string(block_size * 2, 'h'));
8013 ASSERT_TRUE(bl_eq(expected, bl));
8014 }
8015
8016 {
8017 struct store_statfs_t statfs;
8018 int r = store->statfs(&statfs);
8019 ASSERT_EQ(r, 0);
8020 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 2);
8021 ASSERT_LE(statfs.allocated, (unsigned)block_size * 2);
8022 }
8023
8024 {
8025 ObjectStore::Transaction t;
8026 t.remove(cid, hoid);
8027 t.remove(cid, hoid2);
8028 r = queue_transaction(store, ch, std::move(t));
8029 ASSERT_EQ(r, 0);
8030 }
8031
8032 {
8033 ObjectStore::Transaction t;
8034 bufferlist bl;
8035 bl.append(std::string(block_size * 32, 'a'));
8036
8037 // this will create two 128K aligned blobs
8038 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8039 t.write(cid, hoid, bl.length(), bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8040 r = queue_transaction(store, ch, std::move(t));
8041 ASSERT_EQ(r, 0);
8042 }
8043 ASSERT_EQ(logger->get(l_bluestore_write_big), 10u);
8044 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 4u);
8045
8046 // check whether overwrite (less than prefer_deferred_size) partially overlapping two adjacent blobs goes
8047 // deferred
8048 {
8049 ObjectStore::Transaction t;
8050 bufferlist bl;
8051 bl.append(std::string(block_size * 3, 'b'));
8052
8053 t.write(cid, hoid, 0x20000 - block_size, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8054 r = queue_transaction(store, ch, std::move(t));
8055 ASSERT_EQ(r, 0);
8056 }
8057 ASSERT_EQ(logger->get(l_bluestore_write_big), 11u);
8058 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 6u);
8059
8060 {
8061 bufferlist bl, expected;
8062 r = store->read(ch, hoid, 0, 0x20000 - block_size, bl);
8063 ASSERT_EQ(r, 0x20000 - block_size);
8064 expected.append(string(r, 'a'));
8065 ASSERT_TRUE(bl_eq(expected, bl));
8066 expected.clear();
8067
8068 r = store->read(ch, hoid, 0x20000 - block_size, block_size * 3, bl);
8069 ASSERT_EQ(r, 3 * block_size);
8070 expected.append(string(r, 'b'));
8071 ASSERT_TRUE(bl_eq(expected, bl));
8072 expected.clear();
8073
8074 r = store->read(ch, hoid, 0x20000 + 2 * block_size, block_size * 30, bl);
8075 ASSERT_EQ(r, 30 * block_size);
8076 expected.append(string(r, 'a'));
8077 ASSERT_TRUE(bl_eq(expected, bl));
8078 expected.clear();
8079 }
8080
8081 {
8082 struct store_statfs_t statfs;
8083 int r = store->statfs(&statfs);
8084 ASSERT_EQ(r, 0);
8085 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 64);
8086 ASSERT_LE(statfs.allocated, (unsigned)block_size * 64);
8087 }
8088
8089 // check whether overwrite (larger than prefer_deferred_size) partially
8090 // overlapping two adjacent blobs goes deferred
8091 {
8092 ObjectStore::Transaction t;
8093 bufferlist bl;
8094 bl.append(std::string(block_size * 30, 'c'));
8095
8096 t.write(cid, hoid, 0x10000 + block_size, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8097 r = queue_transaction(store, ch, std::move(t));
8098 ASSERT_EQ(r, 0);
8099 }
8100 sleep(2);
8101 ASSERT_EQ(logger->get(l_bluestore_write_big), 12u);
8102 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 8u);
8103
8104 {
8105 bufferlist bl, expected;
8106 r = store->read(ch, hoid, 0, 0x11000, bl);
8107 ASSERT_EQ(r, 0x11000);
8108 expected.append(string(r, 'a'));
8109 ASSERT_TRUE(bl_eq(expected, bl));
8110 expected.clear();
8111
8112 r = store->read(ch, hoid, 0x11000, block_size * 30, bl);
8113 ASSERT_EQ(r, block_size * 30);
8114 expected.append(string(r, 'c'));
8115 ASSERT_TRUE(bl_eq(expected, bl));
8116 expected.clear();
8117
8118 r = store->read(ch, hoid, block_size * 47, 0x10000 + block_size, bl);
8119 ASSERT_EQ(r, 0x10000 + block_size);
8120 expected.append(string(r, 'a'));
8121 ASSERT_TRUE(bl_eq(expected, bl));
8122 expected.clear();
8123 }
8124
8125 {
8126 struct store_statfs_t statfs;
8127 int r = store->statfs(&statfs);
8128 ASSERT_EQ(r, 0);
8129 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 64);
8130 ASSERT_LE(statfs.allocated, (unsigned)block_size * 64);
8131 }
8132
8133 logger->reset();
8134 // check whether overwrite (prefer_deferred_size < 120K < 2 * prefer_defer_size) partially
8135 // overlapping two adjacent blobs goes partly deferred
8136 {
8137 ObjectStore::Transaction t;
8138 bufferlist bl;
8139 bl.append(std::string(block_size * 30, 'e'));
8140
8141 t.write(cid, hoid, 0x20000 - block_size, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8142 r = queue_transaction(store, ch, std::move(t));
8143 ASSERT_EQ(r, 0);
8144 }
8145 sleep(2);
8146 ASSERT_EQ(logger->get(l_bluestore_write_big), 1u);
8147 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 1u);
8148 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_writes), 1u);
8149 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_write_bytes), block_size);
8150
8151 {
8152 struct store_statfs_t statfs;
8153 int r = store->statfs(&statfs);
8154 ASSERT_EQ(r, 0);
8155 ASSERT_EQ(statfs.data_stored, (unsigned)block_size * 64);
8156 ASSERT_LE(statfs.allocated, (unsigned)block_size * 64);
8157 }
8158
8159 {
8160 ObjectStore::Transaction t;
8161 t.remove(cid, hoid);
8162 t.remove(cid, hoid2);
8163 t.remove_collection(cid);
8164 cerr << "Cleaning" << std::endl;
8165 r = queue_transaction(store, ch, std::move(t));
8166 ASSERT_EQ(r, 0);
8167 }
8168 }
8169
8170 TEST_P(StoreTestSpecificAUSize, DeferredOnBigOverwrite2) {
8171
8172 if (string(GetParam()) != "bluestore")
8173 return;
8174 if (smr) {
8175 cout << "SKIP: no deferred" << std::endl;
8176 return;
8177 }
8178
8179 size_t block_size = 4096;
8180 StartDeferred(block_size);
8181 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8182 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
8183
8184 g_conf().apply_changes(nullptr);
8185
8186 int r;
8187 coll_t cid;
8188 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
8189
8190 PerfCounters* logger = const_cast<PerfCounters*>(store->get_perf_counters());
8191
8192 auto ch = store->create_new_collection(cid);
8193 {
8194 ObjectStore::Transaction t;
8195 t.create_collection(cid, 0);
8196 r = queue_transaction(store, ch, std::move(t));
8197 ASSERT_EQ(r, 0);
8198 }
8199 {
8200 ObjectStore::Transaction t;
8201 bufferlist bl;
8202
8203 bl.append(std::string(128 * 1024, 'c'));
8204
8205 t.write(cid, hoid, 0x1000, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8206 r = queue_transaction(store, ch, std::move(t));
8207 ASSERT_EQ(r, 0);
8208 ASSERT_EQ(logger->get(l_bluestore_write_big), 1u);
8209 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), bl.length());
8210 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 3u);
8211 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 0u);
8212 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_writes), 0u);
8213 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_write_bytes), 0);
8214 }
8215
8216 logger->reset();
8217 {
8218 ObjectStore::Transaction t;
8219 bufferlist bl;
8220
8221 bl.append(std::string(128 * 1024, 'c'));
8222
8223 t.write(cid, hoid, 0x2000, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8224 r = queue_transaction(store, ch, std::move(t));
8225 ASSERT_EQ(r, 0);
8226
8227 ASSERT_EQ(logger->get(l_bluestore_write_big), 1u);
8228 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), bl.length());
8229 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 3u);
8230 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 1u);
8231 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_writes), 1u);
8232 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_write_bytes), 57344);
8233 }
8234
8235 {
8236 ObjectStore::Transaction t;
8237 t.remove(cid, hoid);
8238 t.remove(cid, hoid);
8239 t.remove_collection(cid);
8240 cerr << "Cleaning" << std::endl;
8241 r = queue_transaction(store, ch, std::move(t));
8242 ASSERT_EQ(r, 0);
8243 }
8244 }
8245
8246 TEST_P(StoreTestSpecificAUSize, DeferredOnBigOverwrite3) {
8247
8248 if (string(GetParam()) != "bluestore")
8249 return;
8250 if (smr) {
8251 cout << "SKIP: no deferred" << std::endl;
8252 return;
8253 }
8254
8255 size_t block_size = 4096;
8256 StartDeferred(block_size);
8257 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8258 SetVal(g_conf(), "bluestore_prefer_deferred_size", "65536");
8259
8260 g_conf().apply_changes(nullptr);
8261
8262 int r;
8263 coll_t cid;
8264 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
8265
8266 PerfCounters* logger = const_cast<PerfCounters*>(store->get_perf_counters());
8267
8268 auto ch = store->create_new_collection(cid);
8269 {
8270 ObjectStore::Transaction t;
8271 t.create_collection(cid, 0);
8272 r = queue_transaction(store, ch, std::move(t));
8273 ASSERT_EQ(r, 0);
8274 }
8275
8276 logger->reset();
8277 {
8278 ObjectStore::Transaction t;
8279 bufferlist bl;
8280
8281 bl.append(std::string(4096 * 1024, 'c'));
8282
8283 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8284 r = queue_transaction(store, ch, std::move(t));
8285 ASSERT_EQ(r, 0);
8286
8287 ASSERT_EQ(logger->get(l_bluestore_write_big), 1u);
8288 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), bl.length());
8289 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 64u);
8290 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 0u);
8291 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_writes), 0u);
8292 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_write_bytes), 0u);
8293 }
8294 logger->reset();
8295 {
8296 ObjectStore::Transaction t;
8297 bufferlist bl;
8298
8299 bl.append(std::string(4096 * 1024, 'c'));
8300
8301 t.write(cid, hoid, 0x1000, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8302 r = queue_transaction(store, ch, std::move(t));
8303 ASSERT_EQ(r, 0);
8304
8305 ASSERT_EQ(logger->get(l_bluestore_write_big), 1u);
8306 ASSERT_EQ(logger->get(l_bluestore_write_big_bytes), bl.length());
8307 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 65u);
8308 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), 1u);
8309 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_writes), 1u);
8310 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_write_bytes), 61440);
8311 }
8312 {
8313 ObjectStore::Transaction t;
8314 t.remove(cid, hoid);
8315 t.remove_collection(cid);
8316 cerr << "Cleaning" << std::endl;
8317 r = queue_transaction(store, ch, std::move(t));
8318 ASSERT_EQ(r, 0);
8319 }
8320 }
8321
8322 TEST_P(StoreTestSpecificAUSize, DeferredDifferentChunks) {
8323
8324 if (string(GetParam()) != "bluestore")
8325 return;
8326 if (smr) {
8327 cout << "SKIP: no deferred" << std::endl;
8328 return;
8329 }
8330
8331 size_t alloc_size = 4096;
8332 size_t large_object_size = 1 * 1024 * 1024;
8333 size_t prefer_deferred_size = 65536;
8334 StartDeferred(alloc_size);
8335 SetVal(g_conf(), "bluestore_max_blob_size", "131072");
8336 SetVal(g_conf(), "bluestore_prefer_deferred_size",
8337 stringify(prefer_deferred_size).c_str());
8338 g_conf().apply_changes(nullptr);
8339
8340 int r;
8341 coll_t cid;
8342 const PerfCounters* logger = store->get_perf_counters();
8343 size_t exp_bluestore_write_big = 0;
8344 size_t exp_bluestore_write_big_deferred = 0;
8345
8346 ObjectStore::CollectionHandle ch = store->create_new_collection(cid);
8347 {
8348 ObjectStore::Transaction t;
8349 t.create_collection(cid, 0);
8350 r = queue_transaction(store, ch, std::move(t));
8351 ASSERT_EQ(r, 0);
8352 }
8353 for (size_t expected_write_size = 1024; expected_write_size <= prefer_deferred_size; expected_write_size *= 2) {
8354 //create object with hint
8355 ghobject_t hoid(hobject_t("test-"+to_string(expected_write_size), "", CEPH_NOSNAP, 0, -1, ""));
8356 {
8357 ObjectStore::Transaction t;
8358 t.touch(cid, hoid);
8359 t.set_alloc_hint(cid, hoid, large_object_size, expected_write_size,
8360 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ |
8361 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY);
8362 r = queue_transaction(store, ch, std::move(t));
8363 ASSERT_EQ(r, 0);
8364 }
8365
8366 //fill object
8367 {
8368 ObjectStore::Transaction t;
8369 bufferlist bl;
8370 bl.append(std::string(large_object_size, 'h'));
8371 t.write(cid, hoid, 0, bl.length(), bl,
8372 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8373 r = queue_transaction(store, ch, std::move(t));
8374 ++exp_bluestore_write_big;
8375 ASSERT_EQ(r, 0);
8376 }
8377 ASSERT_EQ(logger->get(l_bluestore_write_big), exp_bluestore_write_big);
8378 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), exp_bluestore_write_big_deferred);
8379
8380 // check whether write will properly use deferred
8381 {
8382 ObjectStore::Transaction t;
8383 bufferlist bl;
8384 bl.append(std::string(alloc_size + 2, 'z'));
8385 t.write(cid, hoid, large_object_size - 2 * alloc_size - 1, bl.length(), bl,
8386 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8387 r = queue_transaction(store, ch, std::move(t));
8388 ++exp_bluestore_write_big;
8389 if (expected_write_size < prefer_deferred_size)
8390 ++exp_bluestore_write_big_deferred;
8391 ASSERT_EQ(r, 0);
8392 }
8393 ASSERT_EQ(logger->get(l_bluestore_write_big), exp_bluestore_write_big);
8394 ASSERT_EQ(logger->get(l_bluestore_write_big_deferred), exp_bluestore_write_big_deferred);
8395 }
8396 ch.reset(nullptr);
8397 CloseAndReopen();
8398 ch = store->open_collection(cid);
8399 // check values
8400 for (size_t expected_write_size = 1024; expected_write_size <= 65536; expected_write_size *= 2) {
8401 ghobject_t hoid(hobject_t("test-"+to_string(expected_write_size), "", CEPH_NOSNAP, 0, -1, ""));
8402 {
8403 bufferlist bl, expected;
8404 r = store->read(ch, hoid, 0, large_object_size, bl);
8405 ASSERT_EQ(r, large_object_size);
8406 expected.append(string(large_object_size - 2 * alloc_size - 1, 'h'));
8407 expected.append(string(alloc_size + 2, 'z'));
8408 expected.append(string(alloc_size - 1, 'h'));
8409 ASSERT_TRUE(bl_eq(expected, bl));
8410 }
8411 }
8412 {
8413 ObjectStore::Transaction t;
8414 for (size_t expected_write_size = 1024; expected_write_size <= 65536; expected_write_size *= 2) {
8415 ghobject_t hoid(hobject_t("test-"+to_string(expected_write_size), "", CEPH_NOSNAP, 0, -1, ""));
8416 t.remove(cid, hoid);
8417 }
8418 t.remove_collection(cid);
8419 cerr << "Cleaning" << std::endl;
8420 r = queue_transaction(store, ch, std::move(t));
8421 ASSERT_EQ(r, 0);
8422 }
8423 }
8424
8425 TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwriteReverse) {
8426
8427 if (string(GetParam()) != "bluestore")
8428 return;
8429 if (smr) {
8430 cout << "SKIP: no overwrite" << std::endl;
8431 return;
8432 }
8433
8434 size_t block_size = 4096;
8435 StartDeferred(block_size);
8436 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8437 g_conf().apply_changes(nullptr);
8438
8439 int r;
8440 coll_t cid;
8441 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
8442
8443 auto ch = store->create_new_collection(cid);
8444
8445 const PerfCounters* logger = store->get_perf_counters();
8446 {
8447 ObjectStore::Transaction t;
8448 t.create_collection(cid, 0);
8449 r = queue_transaction(store, ch, std::move(t));
8450 ASSERT_EQ(r, 0);
8451 }
8452 {
8453 ObjectStore::Transaction t;
8454 bufferlist bl;
8455
8456 bl.append(std::string(block_size * 2, 'a'));
8457 t.write(cid, hoid, block_size * 10, bl.length(), bl,
8458 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8459 r = queue_transaction(store, ch, std::move(t));
8460 ASSERT_EQ(r, 0);
8461 }
8462 {
8463 // prepend existing
8464 ObjectStore::Transaction t;
8465 bufferlist bl;
8466
8467 bl.append(std::string(block_size, 'b'));
8468 t.write(cid, hoid, block_size * 9, bl.length(), bl,
8469 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8470 r = queue_transaction(store, ch, std::move(t));
8471 ASSERT_EQ(r, 0);
8472 }
8473 {
8474 // We need to issue a read to trigger cache stat update that refresh
8475 // perf counters. additionally we need to wait some time for mempool
8476 // thread to update stats.
8477 sleep(1);
8478 bufferlist bl, expected;
8479 r = store->read(ch, hoid, block_size * 9, block_size * 2, bl);
8480 ASSERT_EQ(r, (int)block_size * 2);
8481 expected.append(string(block_size, 'b'));
8482 expected.append(string(block_size, 'a'));
8483 ASSERT_TRUE(bl_eq(expected, bl));
8484 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
8485 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
8486 }
8487
8488
8489 {
8490 // prepend existing with a gap
8491 ObjectStore::Transaction t;
8492 bufferlist bl;
8493
8494 bl.append(std::string(block_size, 'c'));
8495 t.write(cid, hoid, block_size * 7, bl.length(), bl,
8496 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8497 r = queue_transaction(store, ch, std::move(t));
8498 ASSERT_EQ(r, 0);
8499 }
8500 {
8501 // We need to issue a read to trigger cache stat update that refresh
8502 // perf counters. additionally we need to wait some time for mempool
8503 // thread to update stats.
8504 sleep(1);
8505 bufferlist bl, expected;
8506 r = store->read(ch, hoid, block_size * 7, block_size * 3, bl);
8507 ASSERT_EQ(r, (int)block_size * 3);
8508 expected.append(string(block_size, 'c'));
8509 expected.append(string(block_size, 0));
8510 expected.append(string(block_size, 'b'));
8511 ASSERT_TRUE(bl_eq(expected, bl));
8512 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
8513 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
8514 }
8515
8516 {
8517 // append after existing with a gap
8518 ObjectStore::Transaction t;
8519 bufferlist bl;
8520
8521 bl.append(std::string(block_size, 'd'));
8522 t.write(cid, hoid, block_size * 13, bl.length(), bl,
8523 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8524 r = queue_transaction(store, ch, std::move(t));
8525 ASSERT_EQ(r, 0);
8526 }
8527 {
8528 // We need to issue a read to trigger cache stat update that refresh
8529 // perf counters. additionally we need to wait some time for mempool
8530 // thread to update stats.
8531 sleep(1);
8532 bufferlist bl, expected;
8533 r = store->read(ch, hoid, block_size * 11, block_size * 3, bl);
8534 ASSERT_EQ(r, (int)block_size * 3);
8535 expected.append(string(block_size, 'a'));
8536 expected.append(string(block_size, 0));
8537 expected.append(string(block_size, 'd'));
8538 ASSERT_TRUE(bl_eq(expected, bl));
8539 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
8540 ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
8541 }
8542
8543 {
8544 // append twice to the next max_blob slot
8545 ObjectStore::Transaction t;
8546 bufferlist bl;
8547
8548 bl.append(std::string(block_size, 'e'));
8549 t.write(cid, hoid, block_size * 17, bl.length(), bl,
8550 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8551 t.write(cid, hoid, block_size * 19, bl.length(), bl,
8552 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8553 r = queue_transaction(store, ch, std::move(t));
8554 ASSERT_EQ(r, 0);
8555 }
8556 {
8557 // We need to issue a read to trigger cache stat update that refresh
8558 // perf counters. additionally we need to wait some time for mempool
8559 // thread to update stats.
8560 sleep(1);
8561 bufferlist bl, expected;
8562 r = store->read(ch, hoid, block_size * 17, block_size * 3, bl);
8563 ASSERT_EQ(r, (int)block_size * 3);
8564 expected.append(string(block_size, 'e'));
8565 expected.append(string(block_size, 0));
8566 expected.append(string(block_size, 'e'));
8567 ASSERT_TRUE(bl_eq(expected, bl));
8568 ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
8569 ASSERT_EQ(logger->get(l_bluestore_extents), 5u);
8570 }
8571 {
8572 // fill gaps at the second slot
8573 ObjectStore::Transaction t;
8574 bufferlist bl;
8575
8576 bl.append(std::string(block_size, 'f'));
8577 t.write(cid, hoid, block_size * 16, bl.length(), bl,
8578 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8579 t.write(cid, hoid, block_size * 18, bl.length(), bl,
8580 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8581 r = queue_transaction(store, ch, std::move(t));
8582 ASSERT_EQ(r, 0);
8583 }
8584 {
8585 // We need to issue a read to trigger cache stat update that refresh
8586 // perf counters. additionally we need to wait some time for mempool
8587 // thread to update stats.
8588 sleep(1);
8589 bufferlist bl, expected;
8590 r = store->read(ch, hoid, block_size * 16, block_size * 4, bl);
8591 ASSERT_EQ(r, (int)block_size * 4);
8592 expected.append(string(block_size, 'f'));
8593 expected.append(string(block_size, 'e'));
8594 expected.append(string(block_size, 'f'));
8595 expected.append(string(block_size, 'e'));
8596 ASSERT_TRUE(bl_eq(expected, bl));
8597 ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
8598 ASSERT_EQ(logger->get(l_bluestore_extents), 4u);
8599 }
8600 {
8601 ObjectStore::Transaction t;
8602 t.remove(cid, hoid);
8603 t.remove_collection(cid);
8604 cerr << "Cleaning" << std::endl;
8605 r = queue_transaction(store, ch, std::move(t));
8606 ASSERT_EQ(r, 0);
8607 }
8608 }
8609
8610 TEST_P(StoreTestSpecificAUSize, BlobReuseOnSmallOverwrite) {
8611
8612 if (string(GetParam()) != "bluestore")
8613 return;
8614 if (smr) {
8615 cout << "SKIP: no overwrite" << std::endl;
8616 return;
8617 }
8618
8619 size_t block_size = 4096;
8620 StartDeferred(block_size);
8621 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
8622 g_conf().apply_changes(nullptr);
8623
8624 int r;
8625 coll_t cid;
8626 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
8627
8628 const PerfCounters* logger = store->get_perf_counters();
8629 auto ch = store->create_new_collection(cid);
8630
8631 {
8632 ObjectStore::Transaction t;
8633 t.create_collection(cid, 0);
8634 r = queue_transaction(store, ch, std::move(t));
8635 ASSERT_EQ(r, 0);
8636 }
8637 {
8638 ObjectStore::Transaction t;
8639 bufferlist bl;
8640
8641 bl.append(std::string(block_size, 'a'));
8642 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8643 t.write(cid, hoid, block_size * 2, bl.length(), bl,
8644 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8645 r = queue_transaction(store, ch, std::move(t));
8646 ASSERT_EQ(r, 0);
8647 }
8648 {
8649 // write small into the gap
8650 ObjectStore::Transaction t;
8651 bufferlist bl;
8652
8653 bl.append(std::string(3, 'b'));
8654 t.write(cid, hoid, block_size + 1, bl.length(), bl,
8655 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
8656 r = queue_transaction(store, ch, std::move(t));
8657 ASSERT_EQ(r, 0);
8658 }
8659 {
8660 // We need to issue a read to trigger cache stat update that refresh
8661 // perf counters. additionally we need to wait some time for mempool
8662 // thread to update stats.
8663 sleep(1);
8664 bufferlist bl, expected;
8665 r = store->read(ch, hoid, 0, block_size * 3, bl);
8666 ASSERT_EQ(r, (int)block_size * 3);
8667 expected.append(string(block_size, 'a'));
8668 expected.append(string(1, 0));
8669 expected.append(string(3, 'b'));
8670 expected.append(string(block_size - 4, 0));
8671 expected.append(string(block_size, 'a'));
8672 ASSERT_TRUE(bl_eq(expected, bl));
8673
8674 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
8675 ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
8676 }
8677 {
8678 ObjectStore::Transaction t;
8679 t.remove(cid, hoid);
8680 t.remove_collection(cid);
8681 cerr << "Cleaning" << std::endl;
8682 r = queue_transaction(store, ch, std::move(t));
8683 ASSERT_EQ(r, 0);
8684 }
8685 }
8686
8687 // The test case to reproduce an issue when write happens
8688 // to a zero space between the extents sharing the same spanning blob
8689 // with unloaded shard map.
8690 // Second extent might be filled with zeros this way due to wrong result
8691 // returned by has_any_extents() call in do_write_small. The latter is caused
8692 // by incompletly loaded extent map.
8693 TEST_P(StoreTestSpecificAUSize, SmallWriteOnShardedExtents) {
8694 if (string(GetParam()) != "bluestore")
8695 return;
8696
8697 size_t block_size = 0x10000;
8698 StartDeferred(block_size);
8699
8700 SetVal(g_conf(), "bluestore_csum_type", "xxhash64");
8701 SetVal(g_conf(), "bluestore_max_blob_size", "524288"); // for sure
8702
8703 g_conf().apply_changes(nullptr);
8704
8705 int r;
8706 coll_t cid;
8707 ghobject_t hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
8708 auto ch = store->create_new_collection(cid);
8709
8710 {
8711 ObjectStore::Transaction t;
8712 t.create_collection(cid, 0);
8713 r = queue_transaction(store, ch, std::move(t));
8714 ASSERT_EQ(r, 0);
8715 }
8716 {
8717 //doing some tricks to have sharded extents/spanning objects
8718 ObjectStore::Transaction t;
8719 bufferlist bl, bl2;
8720
8721 bl.append(std::string(0x80000, 'a'));
8722 t.write(cid, hoid1, 0, bl.length(), bl, 0);
8723 t.zero(cid, hoid1, 0x719e0, 0x75b0 );
8724 r = queue_transaction(store, ch, std::move(t));
8725 ASSERT_EQ(r, 0);
8726
8727 bl2.append(std::string(0x70000, 'b'));
8728 t.write(cid, hoid1, 0, bl2.length(), bl2, 0);
8729 t.zero(cid, hoid1, 0, 0x50000);
8730 r = queue_transaction(store, ch, std::move(t));
8731 ASSERT_EQ(r, 0);
8732
8733 }
8734 ch.reset();
8735 store->umount();
8736 store->mount();
8737 ch = store->open_collection(cid);
8738
8739 {
8740 // do a write to zero space in between some extents sharing the same blob
8741 ObjectStore::Transaction t;
8742 bufferlist bl, bl2;
8743
8744 bl.append(std::string(0x6520, 'c'));
8745 t.write(cid, hoid1, 0x71c00, bl.length(), bl, 0);
8746
8747 r = queue_transaction(store, ch, std::move(t));
8748 ASSERT_EQ(r, 0);
8749 }
8750
8751 {
8752 ObjectStore::Transaction t;
8753 bufferlist bl, expected;
8754
8755 r = store->read(ch, hoid1, 0x70000, 0x9c00, bl);
8756 ASSERT_EQ(r, (int)0x9c00);
8757 expected.append(string(0x19e0, 'a'));
8758 expected.append(string(0x220, 0));
8759 expected.append(string(0x6520, 'c'));
8760 expected.append(string(0xe70, 0));
8761 expected.append(string(0xc70, 'a'));
8762 ASSERT_TRUE(bl_eq(expected, bl));
8763 bl.clear();
8764
8765 }
8766
8767 {
8768 ObjectStore::Transaction t;
8769 t.remove(cid, hoid1);
8770 t.remove_collection(cid);
8771 cerr << "Cleaning" << std::endl;
8772 r = queue_transaction(store, ch, std::move(t));
8773 ASSERT_EQ(r, 0);
8774 }
8775 }
8776
8777 TEST_P(StoreTestSpecificAUSize, ReproBug56488Test) {
8778
8779 if (string(GetParam()) != "bluestore")
8780 return;
8781 if (smr) {
8782 cout << "SKIP: no deferred" << std::endl;
8783 return;
8784 }
8785
8786 size_t alloc_size = 65536;
8787 size_t write_size = 4096;
8788 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
8789 SetVal(g_conf(), "bluestore_block_db_create", "true");
8790 SetVal(g_conf(), "bluestore_block_db_size", stringify(1 << 30).c_str());
8791
8792 g_conf().apply_changes(nullptr);
8793 StartDeferred(alloc_size);
8794
8795 int r;
8796 coll_t cid;
8797 const PerfCounters* logger = store->get_perf_counters();
8798
8799 ObjectStore::CollectionHandle ch = store->create_new_collection(cid);
8800 {
8801 ObjectStore::Transaction t;
8802 t.create_collection(cid, 0);
8803 r = queue_transaction(store, ch, std::move(t));
8804 ASSERT_EQ(r, 0);
8805 }
8806 {
8807 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
8808 {
8809 ObjectStore::Transaction t;
8810 t.touch(cid, hoid);
8811 r = queue_transaction(store, ch, std::move(t));
8812 ASSERT_EQ(r, 0);
8813 }
8814
8815 auto issued_dw = logger->get(l_bluestore_issued_deferred_writes);
8816 auto issued_dw_bytes = logger->get(l_bluestore_issued_deferred_write_bytes);
8817 {
8818 ObjectStore::Transaction t;
8819 bufferlist bl;
8820 bl.append(std::string(write_size, 'x'));
8821 t.write(cid, hoid, 0, bl.length(), bl,
8822 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8823 r = queue_transaction(store, ch, std::move(t));
8824 ASSERT_EQ(r, 0);
8825 }
8826 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_writes), issued_dw + 1);
8827 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_write_bytes),
8828 issued_dw_bytes + write_size);
8829 }
8830 {
8831 ghobject_t hoid(hobject_t("test-a", "", CEPH_NOSNAP, 0, -1, ""));
8832 {
8833 ObjectStore::Transaction t;
8834 t.touch(cid, hoid);
8835 r = queue_transaction(store, ch, std::move(t));
8836 ASSERT_EQ(r, 0);
8837 }
8838
8839 auto issued_dw = logger->get(l_bluestore_issued_deferred_writes);
8840 auto issued_dw_bytes = logger->get(l_bluestore_issued_deferred_write_bytes);
8841 {
8842 ObjectStore::Transaction t;
8843 bufferlist bl;
8844 bl.append(std::string(write_size * 2, 'x'));
8845 t.write(cid, hoid, alloc_size - write_size, bl.length(), bl,
8846 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
8847 r = queue_transaction(store, ch, std::move(t));
8848 ASSERT_EQ(r, 0);
8849 }
8850 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_writes), issued_dw + 2);
8851 ASSERT_EQ(logger->get(l_bluestore_issued_deferred_write_bytes),
8852 issued_dw_bytes + write_size * 2);
8853 }
8854 {
8855 ObjectStore::Transaction t;
8856 ghobject_t hoid(hobject_t("test", "", CEPH_NOSNAP, 0, -1, ""));
8857 t.remove(cid, hoid);
8858 ghobject_t hoid_a(hobject_t("test-a", "", CEPH_NOSNAP, 0, -1, ""));
8859 t.remove(cid, hoid_a);
8860 t.remove_collection(cid);
8861 cerr << "Cleaning" << std::endl;
8862 r = queue_transaction(store, ch, std::move(t));
8863 ASSERT_EQ(r, 0);
8864 }
8865 }
8866
8867 #endif //#if defined(WITH_BLUESTORE)
8868
8869 TEST_P(StoreTest, KVDBHistogramTest) {
8870 if (string(GetParam()) != "bluestore")
8871 return;
8872
8873 int NUM_OBJS = 200;
8874 int r = 0;
8875 coll_t cid;
8876 string base("testobj.");
8877 bufferlist a;
8878 bufferptr ap(0x1000);
8879 memset(ap.c_str(), 'a', 0x1000);
8880 a.append(ap);
8881 auto ch = store->create_new_collection(cid);
8882 {
8883 ObjectStore::Transaction t;
8884 t.create_collection(cid, 0);
8885 r = queue_transaction(store, ch, std::move(t));
8886 ASSERT_EQ(r, 0);
8887 }
8888 for (int i = 0; i < NUM_OBJS; ++i) {
8889 ObjectStore::Transaction t;
8890 char buf[100];
8891 snprintf(buf, sizeof(buf), "%d", i);
8892 ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
8893 t.write(cid, hoid, 0, 0x1000, a);
8894 r = queue_transaction(store, ch, std::move(t));
8895 ASSERT_EQ(r, 0);
8896 }
8897
8898 std::unique_ptr<Formatter> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8899 store->generate_db_histogram(f.get());
8900 f->flush(cout);
8901 cout << std::endl;
8902 }
8903
8904 TEST_P(StoreTest, KVDBStatsTest) {
8905 if (string(GetParam()) != "bluestore")
8906 return;
8907
8908 SetVal(g_conf(), "rocksdb_perf", "true");
8909 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
8910 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
8911 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
8912 g_ceph_context->_conf.apply_changes(nullptr);
8913 int r = store->umount();
8914 ASSERT_EQ(r, 0);
8915 r = store->mount(); //to force rocksdb stats
8916 ASSERT_EQ(r, 0);
8917
8918 int NUM_OBJS = 200;
8919 coll_t cid;
8920 string base("testobj.");
8921 bufferlist a;
8922 bufferptr ap(0x1000);
8923 memset(ap.c_str(), 'a', 0x1000);
8924 a.append(ap);
8925 auto ch = store->create_new_collection(cid);
8926 {
8927 ObjectStore::Transaction t;
8928 t.create_collection(cid, 0);
8929 r = queue_transaction(store, ch, std::move(t));
8930 ASSERT_EQ(r, 0);
8931 }
8932 for (int i = 0; i < NUM_OBJS; ++i) {
8933 ObjectStore::Transaction t;
8934 char buf[100];
8935 snprintf(buf, sizeof(buf), "%d", i);
8936 ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
8937 t.write(cid, hoid, 0, 0x1000, a);
8938 r = queue_transaction(store, ch, std::move(t));
8939 ASSERT_EQ(r, 0);
8940 }
8941
8942 std::unique_ptr<Formatter> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
8943 store->get_db_statistics(f.get());
8944 f->flush(cout);
8945 cout << std::endl;
8946 }
8947
8948 #if defined(WITH_BLUESTORE)
8949 TEST_P(StoreTestSpecificAUSize, garbageCollection) {
8950 int r;
8951 coll_t cid;
8952 int buf_len = 256 * 1024;
8953 int overlap_offset = 64 * 1024;
8954 int write_offset = buf_len;
8955 if (string(GetParam()) != "bluestore")
8956 return;
8957 if (smr) {
8958 cout << "SKIP: assertions about allocations need to be adjusted" << std::endl;
8959 return;
8960 }
8961
8962 #define WRITE_AT(offset, _length) {\
8963 ObjectStore::Transaction t;\
8964 if ((uint64_t)_length != bl.length()) { \
8965 buffer::ptr p(bl.c_str(), _length);\
8966 bufferlist bl_tmp;\
8967 bl_tmp.push_back(p);\
8968 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
8969 } else {\
8970 t.write(cid, hoid, offset, bl.length(), bl);\
8971 }\
8972 r = queue_transaction(store, ch, std::move(t));\
8973 ASSERT_EQ(r, 0);\
8974 }
8975
8976 StartDeferred(65536);
8977
8978 SetVal(g_conf(), "bluestore_compression_max_blob_size", "524288");
8979 SetVal(g_conf(), "bluestore_compression_min_blob_size", "262144");
8980 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
8981 SetVal(g_conf(), "bluestore_compression_mode", "force");
8982 g_conf().apply_changes(nullptr);
8983
8984 auto ch = store->create_new_collection(cid);
8985
8986 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
8987 {
8988 bufferlist in;
8989 r = store->read(ch, hoid, 0, 5, in);
8990 ASSERT_EQ(-ENOENT, r);
8991 }
8992 {
8993 ObjectStore::Transaction t;
8994 t.create_collection(cid, 0);
8995 cerr << "Creating collection " << cid << std::endl;
8996 r = queue_transaction(store, ch, std::move(t));
8997 ASSERT_EQ(r, 0);
8998 }
8999
9000 std::string data;
9001 data.resize(buf_len);
9002
9003 {
9004 {
9005 bool exists = store->exists(ch, hoid);
9006 ASSERT_TRUE(!exists);
9007
9008 ObjectStore::Transaction t;
9009 t.touch(cid, hoid);
9010 cerr << "Creating object " << hoid << std::endl;
9011 r = queue_transaction(store, ch, std::move(t));
9012 ASSERT_EQ(r, 0);
9013
9014 exists = store->exists(ch, hoid);
9015 ASSERT_EQ(true, exists);
9016 }
9017 bufferlist bl;
9018
9019 for(size_t i = 0; i < data.size(); i++)
9020 data[i] = i % 256;
9021
9022 bl.append(data);
9023
9024 {
9025 struct store_statfs_t statfs;
9026 WRITE_AT(0, buf_len);
9027 int r = store->statfs(&statfs);
9028 ASSERT_EQ(r, 0);
9029 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
9030 }
9031 {
9032 struct store_statfs_t statfs;
9033 WRITE_AT(write_offset - 2 * overlap_offset, buf_len);
9034 int r = store->statfs(&statfs);
9035 ASSERT_EQ(r, 0);
9036 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
9037 const PerfCounters* counters = store->get_perf_counters();
9038 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0u);
9039 }
9040
9041 {
9042 struct store_statfs_t statfs;
9043 WRITE_AT(write_offset - overlap_offset, buf_len);
9044 int r = store->statfs(&statfs);
9045 ASSERT_EQ(r, 0);
9046 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
9047 const PerfCounters* counters = store->get_perf_counters();
9048 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x10000u);
9049 }
9050 {
9051 struct store_statfs_t statfs;
9052 WRITE_AT(write_offset - 3 * overlap_offset, buf_len);
9053 int r = store->statfs(&statfs);
9054 ASSERT_EQ(r, 0);
9055 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
9056 const PerfCounters* counters = store->get_perf_counters();
9057 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
9058 }
9059 {
9060 struct store_statfs_t statfs;
9061 WRITE_AT(write_offset + 1, overlap_offset-1);
9062 int r = store->statfs(&statfs);
9063 ASSERT_EQ(r, 0);
9064 ASSERT_EQ(statfs.data_compressed_allocated, 0x20000);
9065 const PerfCounters* counters = store->get_perf_counters();
9066 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
9067 }
9068 {
9069 struct store_statfs_t statfs;
9070 WRITE_AT(write_offset + 1, overlap_offset);
9071 int r = store->statfs(&statfs);
9072 ASSERT_EQ(r, 0);
9073 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
9074 const PerfCounters* counters = store->get_perf_counters();
9075 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x3ffffu);
9076 }
9077 {
9078 struct store_statfs_t statfs;
9079 WRITE_AT(0, buf_len-1);
9080 int r = store->statfs(&statfs);
9081 ASSERT_EQ(r, 0);
9082 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
9083 const PerfCounters* counters = store->get_perf_counters();
9084 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
9085 }
9086 SetVal(g_conf(), "bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
9087 {
9088 struct store_statfs_t statfs;
9089 WRITE_AT(1, overlap_offset-2);
9090 WRITE_AT(overlap_offset * 2 + 1, overlap_offset-2);
9091 int r = store->statfs(&statfs);
9092 ASSERT_EQ(r, 0);
9093 ASSERT_EQ(statfs.data_compressed_allocated, 0x10000);
9094 const PerfCounters* counters = store->get_perf_counters();
9095 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
9096 }
9097 {
9098 struct store_statfs_t statfs;
9099 WRITE_AT(overlap_offset + 1, overlap_offset-2);
9100 int r = store->statfs(&statfs);
9101 ASSERT_EQ(r, 0);
9102 ASSERT_EQ(statfs.data_compressed_allocated, 0x0);
9103 const PerfCounters* counters = store->get_perf_counters();
9104 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40007u);
9105 }
9106 {
9107 ObjectStore::Transaction t;
9108 t.remove(cid, hoid);
9109 cerr << "Cleaning" << std::endl;
9110 r = queue_transaction(store, ch, std::move(t));
9111 ASSERT_EQ(r, 0);
9112 }
9113 }
9114 }
9115
9116 TEST_P(StoreTestSpecificAUSize, fsckOnUnalignedDevice) {
9117 if (string(GetParam()) != "bluestore")
9118 return;
9119
9120 SetVal(g_conf(), "bluestore_block_size",
9121 stringify(0x280005000).c_str()); //10 Gb + 4K
9122 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9123 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9124 StartDeferred(0x4000);
9125 store->umount();
9126 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
9127 store->mount();
9128
9129 }
9130
9131 TEST_P(StoreTestSpecificAUSize, fsckOnUnalignedDevice2) {
9132 if (string(GetParam()) != "bluestore")
9133 return;
9134
9135 SetVal(g_conf(), "bluestore_block_size",
9136 stringify(0x280005000).c_str()); //10 Gb + 20K
9137 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9138 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9139 StartDeferred(0x1000);
9140 store->umount();
9141 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
9142 store->mount();
9143 }
9144
9145 namespace {
9146 ghobject_t make_object(const char* name, int64_t pool) {
9147 sobject_t soid{name, CEPH_NOSNAP};
9148 uint32_t hash = std::hash<sobject_t>{}(soid);
9149 return ghobject_t{hobject_t{soid, "", hash, pool, ""}};
9150 }
9151 }
9152
9153 TEST_P(StoreTestSpecificAUSize, BluestoreRepairTest) {
9154 if (string(GetParam()) != "bluestore")
9155 return;
9156 if (smr) {
9157 cout << "TODO: repair mismatched write pointer (+ dead bytes mismatch)" << std::endl;
9158 return;
9159 }
9160 const size_t offs_base = 65536 / 2;
9161
9162
9163 // Now we need standalone db to pass "false free fix" section below
9164 // Due to new BlueFS allocation model (single allocator for main device)
9165 // it might cause "false free" blob overwrite by BlueFS/DB stuff
9166 // and hence fail the test case and corrupt data.
9167 //
9168
9169 SetVal(g_conf(), "bluestore_block_db_create", "true");
9170 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
9171
9172 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9173 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9174 SetVal(g_conf(), "bluestore_max_blob_size",
9175 stringify(2 * offs_base).c_str());
9176 SetVal(g_conf(), "bluestore_extent_map_shard_max_size", "12000");
9177
9178 StartDeferred(0x10000);
9179
9180 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9181
9182 // fill the store with some data
9183 const uint64_t pool = 555;
9184 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
9185 auto ch = store->create_new_collection(cid);
9186
9187 ghobject_t hoid = make_object("Object 1", pool);
9188 ghobject_t hoid_dup = make_object("Object 1(dup)", pool);
9189 ghobject_t hoid2 = make_object("Object 2", pool);
9190 ghobject_t hoid_cloned = hoid2;
9191 hoid_cloned.hobj.snap = 1;
9192 ghobject_t hoid3 = make_object("Object 3", pool);
9193 ghobject_t hoid3_cloned = hoid3;
9194 hoid3_cloned.hobj.snap = 1;
9195 bufferlist bl;
9196 bl.append("1234512345");
9197 int r;
9198 const size_t repeats = 16;
9199 {
9200 auto ch = store->create_new_collection(cid);
9201 cerr << "create collection + write" << std::endl;
9202 ObjectStore::Transaction t;
9203 t.create_collection(cid, 0);
9204 for( auto i = 0ul; i < repeats; ++i ) {
9205 t.write(cid, hoid, i * offs_base, bl.length(), bl);
9206 t.write(cid, hoid_dup, i * offs_base, bl.length(), bl);
9207 }
9208 for( auto i = 0ul; i < repeats; ++i ) {
9209 t.write(cid, hoid2, i * offs_base, bl.length(), bl);
9210 }
9211 t.clone(cid, hoid2, hoid_cloned);
9212
9213 r = queue_transaction(store, ch, std::move(t));
9214 ASSERT_EQ(r, 0);
9215 }
9216
9217 bstore->umount();
9218 bool err_was_injected = false;
9219 //////////// leaked pextent fix ////////////
9220 cerr << "fix leaked pextents" << std::endl;
9221 ASSERT_EQ(bstore->fsck(false), 0);
9222 ASSERT_EQ(bstore->repair(false), 0);
9223 bstore->mount();
9224 if (!bstore->has_null_manager()) {
9225 bstore->inject_leaked(0x30000);
9226 err_was_injected = true;
9227 }
9228
9229 bstore->umount();
9230 if (err_was_injected) {
9231 ASSERT_EQ(bstore->fsck(false), 1);
9232 }
9233 ASSERT_EQ(bstore->repair(false), 0);
9234 ASSERT_EQ(bstore->fsck(false), 0);
9235
9236 //////////// false free fix ////////////
9237 cerr << "fix false free pextents" << std::endl;
9238 bstore->mount();
9239 if (!bstore->has_null_manager()) {
9240 bstore->inject_false_free(cid, hoid);
9241 err_was_injected = true;
9242 }
9243 bstore->umount();
9244 if (err_was_injected) {
9245 ASSERT_EQ(bstore->fsck(false), 2);
9246 ASSERT_EQ(bstore->repair(false), 0);
9247 }
9248 ASSERT_EQ(bstore->fsck(false), 0);
9249
9250
9251 ///////// undecodable shared blob key / stray shared blob records ///////
9252 bstore->mount();
9253 cerr << "undecodable shared blob key" << std::endl;
9254 bstore->inject_broken_shared_blob_key("undec1",
9255 bufferlist());
9256 bstore->inject_broken_shared_blob_key("undecodable key 2",
9257 bufferlist());
9258 bstore->inject_broken_shared_blob_key("undecodable key 3",
9259 bufferlist());
9260 bstore->umount();
9261 ASSERT_EQ(bstore->fsck(false), 3);
9262 ASSERT_EQ(bstore->repair(false), 0);
9263 ASSERT_EQ(bstore->fsck(false), 0);
9264
9265 cerr << "misreferencing" << std::endl;
9266 bstore->mount();
9267 bstore->inject_misreference(cid, hoid, cid, hoid_dup, 0);
9268 bstore->inject_misreference(cid, hoid, cid, hoid_dup, (offs_base * repeats) / 2);
9269 bstore->inject_misreference(cid, hoid, cid, hoid_dup, offs_base * (repeats -1) );
9270 int expected_errors = bstore->has_null_manager() ? 3 : 6;
9271 bstore->umount();
9272 ASSERT_EQ(bstore->fsck(false), expected_errors);
9273 ASSERT_EQ(bstore->repair(false), 0);
9274
9275 ASSERT_EQ(bstore->fsck(true), 0);
9276
9277 // reproducing issues #21040 & 20983
9278 SetVal(g_conf(), "bluestore_debug_inject_bug21040", "true");
9279 g_ceph_context->_conf.apply_changes(nullptr);
9280 bstore->mount();
9281
9282 cerr << "repro bug #21040" << std::endl;
9283 {
9284 auto ch = store->open_collection(cid);
9285 {
9286 ObjectStore::Transaction t;
9287 bl.append("0123456789012345");
9288 t.write(cid, hoid3, offs_base, bl.length(), bl);
9289 bl.clear();
9290 bl.append('!');
9291 t.write(cid, hoid3, 0, bl.length(), bl);
9292
9293 r = queue_transaction(store, ch, std::move(t));
9294 ASSERT_EQ(r, 0);
9295 }
9296 {
9297 ObjectStore::Transaction t;
9298 t.clone(cid, hoid3, hoid3_cloned);
9299 r = queue_transaction(store, ch, std::move(t));
9300 ASSERT_EQ(r, 0);
9301 }
9302
9303 bstore->umount();
9304 // depending on statfs tracking we might meet or miss relevant error
9305 // hence error count >= 3
9306 ASSERT_GE(bstore->fsck(false), 3);
9307 ASSERT_LE(bstore->repair(false), 0);
9308 ASSERT_EQ(bstore->fsck(false), 0);
9309 }
9310
9311 cerr << "Zombie spanning blob" << std::endl;
9312 {
9313 bstore->mount();
9314 ghobject_t hoid4 = make_object("Object 4", pool);
9315 auto ch = store->open_collection(cid);
9316 {
9317 bufferlist bl;
9318 string s(0x1000, 'a');
9319 bl.append(s);
9320 ObjectStore::Transaction t;
9321 for(size_t i = 0; i < 0x10; i++) {
9322 t.write(cid, hoid4, i * bl.length(), bl.length(), bl);
9323 }
9324 r = queue_transaction(store, ch, std::move(t));
9325 ASSERT_EQ(r, 0);
9326 }
9327 sleep(5);
9328 {
9329 bstore->inject_zombie_spanning_blob(cid, hoid4, 12345);
9330 bstore->inject_zombie_spanning_blob(cid, hoid4, 23456);
9331 bstore->inject_zombie_spanning_blob(cid, hoid4, 23457);
9332 }
9333
9334 bstore->umount();
9335 ASSERT_EQ(bstore->fsck(false), 1);
9336 ASSERT_LE(bstore->repair(false), 0);
9337 ASSERT_EQ(bstore->fsck(false), 0);
9338 }
9339
9340 //////////// verify invalid statfs ///////////
9341 cerr << "fix invalid statfs" << std::endl;
9342 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9343 SetVal(g_conf(),
9344 "bluestore_debug_inject_allocation_from_file_failure", "1");
9345 store_statfs_t statfs0;
9346 store_statfs_t statfs;
9347 bstore->mount();
9348 ASSERT_EQ(bstore->statfs(&statfs0), 0);
9349 statfs = statfs0;
9350 statfs.allocated += 0x10000;
9351 statfs.data_stored += 0x10000;
9352 ASSERT_FALSE(statfs0 == statfs);
9353 // this enforces global stats usage
9354 bstore->inject_statfs("bluestore_statfs", statfs);
9355 bstore->umount();
9356
9357 ASSERT_GE(bstore->fsck(false), 1); // global stats mismatch might omitted when
9358 // NCB restore is applied. Hence using >= for
9359 // error count
9360 ASSERT_EQ(bstore->repair(false), 0);
9361 ASSERT_EQ(bstore->fsck(false), 0);
9362 ASSERT_EQ(bstore->mount(), 0);
9363 ASSERT_EQ(bstore->statfs(&statfs), 0);
9364 // adjust free/internal meta space to success in comparison
9365 statfs0.available = statfs.available;
9366 statfs0.internal_metadata = statfs.internal_metadata;
9367 ASSERT_EQ(statfs0, statfs);
9368
9369 SetVal(g_conf(),
9370 "bluestore_debug_inject_allocation_from_file_failure", "0");
9371 cerr << "fix invalid statfs2" << std::endl;
9372 ASSERT_EQ(bstore->statfs(&statfs0), 0);
9373 statfs = statfs0;
9374 statfs.allocated += 0x20000;
9375 statfs.data_stored += 0x20000;
9376 ASSERT_FALSE(statfs0 == statfs);
9377 // this enforces global stats usage
9378 bstore->inject_statfs("bluestore_statfs", statfs);
9379 bstore->umount();
9380
9381 ASSERT_EQ(bstore->fsck(false), 2);
9382 ASSERT_EQ(bstore->repair(false), 0);
9383 ASSERT_EQ(bstore->fsck(false), 0);
9384 ASSERT_EQ(bstore->mount(), 0);
9385 ASSERT_EQ(bstore->statfs(&statfs), 0);
9386 // adjust free/internal meta space to success in comparison
9387 statfs0.available = statfs.available;
9388 statfs0.internal_metadata = statfs.internal_metadata;
9389 ASSERT_EQ(statfs0, statfs);
9390
9391 cerr << "Completing" << std::endl;
9392 }
9393
9394 TEST_P(StoreTestSpecificAUSize, BluestoreBrokenZombieRepairTest) {
9395 if (string(GetParam()) != "bluestore")
9396 return;
9397 if (smr) {
9398 cout << "SKIP: smr repair is different" << std::endl;
9399 return;
9400 }
9401 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9402 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9403
9404 StartDeferred(0x10000);
9405
9406 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9407
9408 int r;
9409
9410 cerr << "initializing" << std::endl;
9411 {
9412 const size_t col_count = 16;
9413 const size_t obj_count = 1024;
9414 ObjectStore::CollectionHandle ch[col_count];
9415 ghobject_t hoid[col_count][obj_count];
9416
9417 unique_ptr<coll_t> cid[col_count];
9418
9419 for (size_t i = 0; i < col_count; i++) {
9420 cid[i].reset(new coll_t(spg_t(pg_t(0, i), shard_id_t::NO_SHARD)));
9421 ch[i] = store->create_new_collection(*cid[i]);
9422 for (size_t j = 0; j < obj_count; j++) {
9423 hoid[i][j] = make_object(stringify(j).c_str(), i);
9424 }
9425 }
9426
9427 for (size_t i = 0; i < col_count; i++) {
9428 ObjectStore::Transaction t;
9429 t.create_collection(*cid[i], 0);
9430 r = queue_transaction(store, ch[i], std::move(t));
9431 ASSERT_EQ(r, 0);
9432 }
9433 cerr << "onode preparing" << std::endl;
9434 bufferlist bl;
9435 string s(0x1000, 'a');
9436 bl.append(s);
9437
9438 for (size_t i = 0; i < col_count; i++) {
9439 for (size_t j = 0; j < obj_count; j++) {
9440 ObjectStore::Transaction t;
9441 t.write(*cid[i], hoid[i][j], bl.length(), bl.length(), bl);
9442 r = queue_transaction(store, ch[i], std::move(t));
9443 ASSERT_EQ(r, 0);
9444 }
9445 }
9446 cerr << "Zombie spanning blob injection" << std::endl;
9447
9448 sleep(5);
9449
9450 for (size_t i = 0; i < col_count; i++) {
9451 for (size_t j = 0; j < obj_count; j++) {
9452 bstore->inject_zombie_spanning_blob(*cid[i], hoid[i][j], 12345);
9453 }
9454 }
9455
9456 cerr << "fscking/fixing" << std::endl;
9457 bstore->umount();
9458 ASSERT_EQ(bstore->fsck(false), col_count * obj_count);
9459 ASSERT_LE(bstore->quick_fix(), 0);
9460 ASSERT_EQ(bstore->fsck(false), 0);
9461 }
9462
9463 cerr << "Completing" << std::endl;
9464 bstore->mount();
9465 }
9466
9467 TEST_P(StoreTestSpecificAUSize, BluestoreRepairSharedBlobTest) {
9468 if (string(GetParam()) != "bluestore")
9469 return;
9470 if (smr) {
9471 cout << "TODO: repair mismatched write pointer (+ dead bytes mismatch)" << std::endl;
9472 return;
9473 }
9474
9475 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9476 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9477
9478 const size_t block_size = 0x1000;
9479 StartDeferred(block_size);
9480
9481 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9482
9483 // fill the store with some data
9484 const uint64_t pool = 555;
9485 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
9486 auto ch = store->create_new_collection(cid);
9487
9488 ghobject_t hoid = make_object("Object 1", pool);
9489 ghobject_t hoid_cloned = hoid;
9490 hoid_cloned.hobj.snap = 1;
9491 ghobject_t hoid2 = make_object("Object 2", pool);
9492
9493 string s(block_size, 1);
9494 bufferlist bl;
9495 bl.append(s);
9496 int r;
9497 {
9498 ObjectStore::Transaction t;
9499 t.create_collection(cid, 0);
9500 r = queue_transaction(store, ch, std::move(t));
9501 ASSERT_EQ(r, 0);
9502 }
9503
9504 // check the scenario when shared blob contains
9505 // references to extents from two objects which don't overlapp
9506 // o1 -> 0x2000~1K
9507 // o2 -> 0x4000~1k
9508 cerr << "introduce 2 non-overlapped extents in a shared blob"
9509 << std::endl;
9510 {
9511 ObjectStore::Transaction t;
9512 t.write(cid, hoid, 0, bl.length(), bl);
9513 t.write(cid, hoid2, 0, bl.length(), bl); // to make a gap in allocations
9514 t.write(cid, hoid, block_size * 2 , bl.length(), bl);
9515 t.clone(cid, hoid, hoid_cloned);
9516 t.zero(cid, hoid, 0, bl.length());
9517 t.zero(cid, hoid_cloned, block_size * 2, bl.length());
9518 r = queue_transaction(store, ch, std::move(t));
9519 ASSERT_EQ(r, 0);
9520 }
9521 bstore->umount();
9522 bstore->mount();
9523 {
9524 string key;
9525 _key_encode_u64(1, &key);
9526 bluestore_shared_blob_t sb(1);
9527 sb.ref_map.get(0x822000, block_size);
9528 sb.ref_map.get(0x824000, block_size);
9529 sb.ref_map.get(0x824000, block_size);
9530 bufferlist bl;
9531 encode(sb, bl);
9532 bstore->inject_broken_shared_blob_key(key, bl);
9533 }
9534 bstore->umount();
9535 ASSERT_EQ(bstore->fsck(false), 2);
9536 ASSERT_EQ(bstore->repair(false), 0);
9537 ASSERT_EQ(bstore->fsck(false), 0);
9538
9539 cerr << "Completing" << std::endl;
9540 bstore->mount();
9541 }
9542
9543 TEST_P(StoreTestSpecificAUSize, BluestoreBrokenNoSharedBlobRepairTest) {
9544 if (string(GetParam()) != "bluestore")
9545 return;
9546 if (smr) {
9547 cout << "SKIP: smr repair is different" << std::endl;
9548 return;
9549 }
9550
9551 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9552 SetVal(g_conf(), "bluestore_fsck_on_umount", "false");
9553
9554 StartDeferred(0x10000);
9555
9556 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9557
9558 int r;
9559
9560 // initializing
9561 cerr << "initializing" << std::endl;
9562 {
9563 const uint64_t pool = 555;
9564 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
9565 auto ch = store->create_new_collection(cid);
9566
9567 ghobject_t hoid = make_object("Object", pool);
9568 ghobject_t hoid_cloned = hoid;
9569 hoid_cloned.hobj.snap = 1;
9570
9571 {
9572 ObjectStore::Transaction t;
9573 t.create_collection(cid, 0);
9574 r = queue_transaction(store, ch, std::move(t));
9575 ASSERT_EQ(r, 0);
9576 }
9577 {
9578 ObjectStore::Transaction t;
9579 bufferlist bl;
9580 bl.append("0123456789012345");
9581 t.write(cid, hoid, 0, bl.length(), bl);
9582
9583 r = queue_transaction(store, ch, std::move(t));
9584 ASSERT_EQ(r, 0);
9585 }
9586 {
9587 ObjectStore::Transaction t;
9588 t.clone(cid, hoid, hoid_cloned);
9589 r = queue_transaction(store, ch, std::move(t));
9590 ASSERT_EQ(r, 0);
9591 }
9592 }
9593 // injecting an error and checking
9594 cerr << "injecting" << std::endl;
9595 sleep(3); // need some time for the previous write to land
9596 bstore->inject_no_shared_blob_key();
9597 bstore->inject_stray_shared_blob_key(12345678);
9598
9599 {
9600 cerr << "fscking/fixing" << std::endl;
9601 // we need to check for null-manager before umount()
9602 bool has_null_manager = bstore->has_null_manager();
9603 bstore->umount();
9604 // depending on the allocation map's source we can
9605 // either observe or don't observe an additional
9606 // extent leak detection. Hence adjusting the expected
9607 // value
9608 size_t expected_error_count =
9609 has_null_manager ?
9610 4: // 4 sb ref mismatch errors [+ 1 optional statfs, hence ASSERT_GE]
9611 7; // 4 sb ref mismatch errors + 1 statfs + 1 block leak + 1 non-free
9612 ASSERT_GE(bstore->fsck(false), expected_error_count);
9613 // repair might report less errors than fsck above showed
9614 // as some errors, e.g. statfs mismatch, are implicitly fixed
9615 // before the detection during the previous repair steps...
9616 ASSERT_LE(bstore->repair(false), expected_error_count);
9617 ASSERT_EQ(bstore->fsck(false), 0);
9618 }
9619
9620 cerr << "Completing" << std::endl;
9621 bstore->mount();
9622 }
9623
9624 TEST_P(StoreTest, BluestoreRepairGlobalStats) {
9625 if (string(GetParam()) != "bluestore")
9626 return;
9627 const size_t offs_base = 65536 / 2;
9628
9629 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9630
9631 // start with global stats
9632 bstore->inject_global_statfs({});
9633 bstore->umount();
9634 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9635 bstore->mount();
9636
9637 // fill the store with some data
9638 const uint64_t pool = 555;
9639 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
9640 auto ch = store->create_new_collection(cid);
9641
9642 ghobject_t hoid = make_object("Object 1", pool);
9643 ghobject_t hoid_dup = make_object("Object 1(dup)", pool);
9644 ghobject_t hoid2 = make_object("Object 2", pool);
9645 ghobject_t hoid_cloned = hoid2;
9646 hoid_cloned.hobj.snap = 1;
9647 ghobject_t hoid3 = make_object("Object 3", pool);
9648 ghobject_t hoid3_cloned = hoid3;
9649 hoid3_cloned.hobj.snap = 1;
9650 bufferlist bl;
9651 bl.append("1234512345");
9652 int r;
9653 const size_t repeats = 16;
9654 {
9655 auto ch = store->create_new_collection(cid);
9656 cerr << "create collection + write" << std::endl;
9657 ObjectStore::Transaction t;
9658 t.create_collection(cid, 0);
9659 for( auto i = 0ul; i < repeats; ++i ) {
9660 t.write(cid, hoid, i * offs_base, bl.length(), bl);
9661 t.write(cid, hoid_dup, i * offs_base, bl.length(), bl);
9662 }
9663 for( auto i = 0ul; i < repeats; ++i ) {
9664 t.write(cid, hoid2, i * offs_base, bl.length(), bl);
9665 }
9666 t.clone(cid, hoid2, hoid_cloned);
9667
9668 r = queue_transaction(store, ch, std::move(t));
9669 ASSERT_EQ(r, 0);
9670 }
9671
9672 bstore->umount();
9673
9674 // enable per-pool stats collection hence causing fsck to fail
9675 cerr << "per-pool statfs" << std::endl;
9676 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9677 g_ceph_context->_conf.apply_changes(nullptr);
9678
9679 ASSERT_EQ(bstore->fsck(false), 1);
9680 ASSERT_EQ(bstore->repair(false), 0);
9681 ASSERT_EQ(bstore->fsck(false), 0);
9682
9683 bstore->mount();
9684 }
9685
9686 TEST_P(StoreTest, BluestoreRepairGlobalStatsFixOnMount) {
9687 if (string(GetParam()) != "bluestore")
9688 return;
9689 const size_t offs_base = 65536 / 2;
9690
9691 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9692
9693 // start with global stats
9694 bstore->inject_global_statfs({});
9695 bstore->umount();
9696 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9697 bstore->mount();
9698
9699 // fill the store with some data
9700 const uint64_t pool = 555;
9701 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
9702 auto ch = store->create_new_collection(cid);
9703
9704 ghobject_t hoid = make_object("Object 1", pool);
9705 ghobject_t hoid_dup = make_object("Object 1(dup)", pool);
9706 ghobject_t hoid2 = make_object("Object 2", pool);
9707 ghobject_t hoid_cloned = hoid2;
9708 hoid_cloned.hobj.snap = 1;
9709 ghobject_t hoid3 = make_object("Object 3", pool);
9710 ghobject_t hoid3_cloned = hoid3;
9711 hoid3_cloned.hobj.snap = 1;
9712 bufferlist bl;
9713 bl.append("1234512345");
9714 int r;
9715 const size_t repeats = 16;
9716 {
9717 auto ch = store->create_new_collection(cid);
9718 cerr << "create collection + write" << std::endl;
9719 ObjectStore::Transaction t;
9720 t.create_collection(cid, 0);
9721 for( auto i = 0ul; i < repeats; ++i ) {
9722 t.write(cid, hoid, i * offs_base, bl.length(), bl);
9723 t.write(cid, hoid_dup, i * offs_base, bl.length(), bl);
9724 }
9725 for( auto i = 0ul; i < repeats; ++i ) {
9726 t.write(cid, hoid2, i * offs_base, bl.length(), bl);
9727 }
9728 t.clone(cid, hoid2, hoid_cloned);
9729
9730 r = queue_transaction(store, ch, std::move(t));
9731 ASSERT_EQ(r, 0);
9732 }
9733
9734 bstore->umount();
9735
9736 // enable per-pool stats collection hence causing fsck to fail
9737 cerr << "per-pool statfs" << std::endl;
9738 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_stats", "true");
9739 g_ceph_context->_conf.apply_changes(nullptr);
9740
9741 ASSERT_EQ(bstore->fsck(false), 1);
9742
9743 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9744 bstore->mount();
9745 bstore->umount();
9746 ASSERT_EQ(bstore->fsck(false), 0);
9747
9748 bstore->mount();
9749 }
9750
9751 TEST_P(StoreTest, BluestoreStatistics) {
9752 if (string(GetParam()) != "bluestore")
9753 return;
9754
9755 SetVal(g_conf(), "rocksdb_perf", "true");
9756 SetVal(g_conf(), "rocksdb_collect_compaction_stats", "true");
9757 SetVal(g_conf(), "rocksdb_collect_extended_stats","true");
9758 SetVal(g_conf(), "rocksdb_collect_memory_stats","true");
9759
9760 // disable cache
9761 SetVal(g_conf(), "bluestore_cache_size_ssd", "0");
9762 SetVal(g_conf(), "bluestore_cache_size_hdd", "0");
9763 SetVal(g_conf(), "bluestore_cache_size", "0");
9764 g_ceph_context->_conf.apply_changes(nullptr);
9765
9766 int r = store->umount();
9767 ASSERT_EQ(r, 0);
9768 r = store->mount();
9769 ASSERT_EQ(r, 0);
9770
9771 BlueStore* bstore = NULL;
9772 EXPECT_NO_THROW(bstore = dynamic_cast<BlueStore*> (store.get()));
9773
9774 coll_t cid;
9775 ghobject_t hoid(hobject_t("test_db_statistics", "", CEPH_NOSNAP, 0, 0, ""));
9776 auto ch = bstore->create_new_collection(cid);
9777 bufferlist bl;
9778 bl.append("0123456789abcdefghi");
9779 {
9780 ObjectStore::Transaction t;
9781 t.create_collection(cid, 0);
9782 t.touch(cid, hoid);
9783 t.write(cid, hoid, 0, bl.length(), bl);
9784 cerr << "Write object" << std::endl;
9785 r = queue_transaction(bstore, ch, std::move(t));
9786 ASSERT_EQ(r, 0);
9787 }
9788 {
9789 bufferlist readback;
9790 r = store->read(ch, hoid, 0, bl.length(), readback);
9791 ASSERT_EQ(static_cast<int>(bl.length()), r);
9792 ASSERT_TRUE(bl_eq(bl, readback));
9793 }
9794 std::unique_ptr<Formatter> f(Formatter::create("store_test", "json-pretty", "json-pretty"));
9795 EXPECT_NO_THROW(store->get_db_statistics(f.get()));
9796 f->flush(cout);
9797 cout << std::endl;
9798 }
9799
9800 TEST_P(StoreTest, BluestoreStrayOmapDetection)
9801 {
9802 if (string(GetParam()) != "bluestore")
9803 return;
9804
9805 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9806 const uint64_t pool = 555;
9807 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
9808 ghobject_t oid = make_object("Object 1", pool);
9809 ghobject_t oid2 = make_object("Object 2", pool);
9810 // fill the store with some data
9811 auto ch = store->create_new_collection(cid);
9812 bufferlist h;
9813 h.append("header");
9814 {
9815 ObjectStore::Transaction t;
9816 t.create_collection(cid, 0);
9817 t.touch(cid, oid);
9818 t.omap_setheader(cid, oid, h);
9819 t.touch(cid, oid2);
9820 t.omap_setheader(cid, oid2, h);
9821 int r = queue_transaction(store, ch, std::move(t));
9822 ASSERT_EQ(r, 0);
9823 }
9824
9825 // inject stray omap
9826 bstore->inject_stray_omap(123456, "somename");
9827
9828 bstore->umount();
9829 // check we detect injected stray omap..
9830
9831 ASSERT_EQ(bstore->fsck(false), 1);
9832 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
9833 bstore->mount();
9834 }
9835
9836 TEST_P(StoreTest, BluestorePerPoolOmapFixOnMount)
9837 {
9838 if (string(GetParam()) != "bluestore")
9839 return;
9840
9841 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
9842 const uint64_t pool = 555;
9843 coll_t cid(spg_t(pg_t(0, pool), shard_id_t::NO_SHARD));
9844 ghobject_t oid = make_object("Object 1", pool);
9845 ghobject_t oid2 = make_object("Object 2", pool);
9846 // fill the store with some data
9847 auto ch = store->create_new_collection(cid);
9848 map<string, bufferlist> omap;
9849 bufferlist h;
9850 h.append("header");
9851 {
9852 omap["omap_key"].append("omap value");
9853 ObjectStore::Transaction t;
9854 t.create_collection(cid, 0);
9855 t.touch(cid, oid);
9856 t.omap_setheader(cid, oid, h);
9857 t.touch(cid, oid2);
9858 t.omap_setheader(cid, oid2, h);
9859 int r = queue_transaction(store, ch, std::move(t));
9860 ASSERT_EQ(r, 0);
9861 }
9862
9863 // inject legacy omaps
9864 bstore->inject_legacy_omap();
9865 bstore->inject_legacy_omap(cid, oid);
9866 bstore->inject_legacy_omap(cid, oid2);
9867
9868 bstore->umount();
9869
9870 // check we injected an issue
9871 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "false");
9872 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
9873 g_ceph_context->_conf.apply_changes(nullptr);
9874 ASSERT_EQ(bstore->fsck(false), 3);
9875
9876 // set autofix and mount
9877 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9878 g_ceph_context->_conf.apply_changes(nullptr);
9879 bstore->mount();
9880 bstore->umount();
9881
9882 // check we fixed it..
9883 ASSERT_EQ(bstore->fsck(false), 0);
9884 bstore->mount();
9885
9886 //
9887 // Now repro https://tracker.ceph.com/issues/43824
9888 //
9889 // inject legacy omaps again
9890 bstore->inject_legacy_omap();
9891 bstore->inject_legacy_omap(cid, oid);
9892 bstore->inject_legacy_omap(cid, oid2);
9893 bstore->umount();
9894
9895 // check we injected an issue
9896 SetVal(g_conf(), "bluestore_fsck_quick_fix_on_mount", "true");
9897 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
9898 g_ceph_context->_conf.apply_changes(nullptr);
9899 bstore->mount();
9900 ch = store->open_collection(cid);
9901
9902 {
9903 // write to onode which will partiall revert per-pool
9904 // omap repair done on mount due to #43824.
9905 // And object removal will leave stray per-pool omap recs
9906 //
9907 ObjectStore::Transaction t;
9908 bufferlist bl;
9909 bl.append("data");
9910 //this triggers onode rec update and hence legacy omap
9911 t.write(cid, oid, 0, bl.length(), bl);
9912 t.remove(cid, oid2); // this will trigger stray per-pool omap
9913 int r = queue_transaction(store, ch, std::move(t));
9914 ASSERT_EQ(r, 0);
9915 }
9916 bstore->umount();
9917 // check omap's been fixed.
9918 ASSERT_EQ(bstore->fsck(false), 0); // this will fail without fix for #43824
9919
9920 bstore->mount();
9921 }
9922
9923 class hugepaged_raw;
9924
9925 static bool is_hugepaged(const bufferptr& bp)
9926 {
9927 const auto& ibp =
9928 static_cast<const ceph::buffer_instrumentation::instrumented_bptr&>(bp);
9929 return ibp.is_raw_marked<BlockDevice::hugepaged_raw_marker_t>();
9930 }
9931
9932 // disabled by default b/c of the dependency on huge page ssome test
9933 // environments might not offer without extra configuration.
9934 TEST_P(StoreTestDeferredSetup, DISABLED_BluestoreHugeReads)
9935 {
9936 if (string(GetParam()) != "bluestore") {
9937 return;
9938 }
9939
9940 constexpr static size_t HUGE_BUFFER_SIZE{2_M};
9941 cout << "Configuring huge page pools" << std::endl;
9942 {
9943 SetVal(g_conf(), "bdev_read_preallocated_huge_buffers",
9944 fmt::format("{}=2", HUGE_BUFFER_SIZE).c_str());
9945 SetVal(g_conf(), "bluestore_max_blob_size",
9946 std::to_string(HUGE_BUFFER_SIZE).c_str());
9947 // let's verify the per-IOContext no-cache override
9948 SetVal(g_conf(), "bluestore_default_buffered_read", "true");
9949 g_ceph_context->_conf.apply_changes(nullptr);
9950 }
9951 DeferredSetup();
9952
9953 coll_t cid;
9954 ghobject_t hoid(hobject_t("test_huge_buffers", "", CEPH_NOSNAP, 0, 0, ""));
9955 auto ch = store->create_new_collection(cid);
9956
9957 bufferlist bl;
9958 {
9959 bufferptr bp{HUGE_BUFFER_SIZE};
9960 // non-zeros! Otherwise the deduplication will take place.
9961 ::memset(bp.c_str(), 0x42, HUGE_BUFFER_SIZE);
9962 bl.push_back(std::move(bp));
9963 ASSERT_EQ(bl.get_num_buffers(), 1);
9964 ASSERT_EQ(bl.length(), HUGE_BUFFER_SIZE);
9965 }
9966
9967 cout << "Write object" << std::endl;
9968 {
9969 ObjectStore::Transaction t;
9970 t.create_collection(cid, 0);
9971 t.touch(cid, hoid);
9972 t.write(cid, hoid, 0, bl.length(), bl);
9973 const auto r = queue_transaction(store, ch, std::move(t));
9974 ASSERT_EQ(r, 0);
9975 }
9976
9977 // force cache clear
9978 {
9979 EXPECT_EQ(store->umount(), 0);
9980 EXPECT_EQ(store->mount(), 0);
9981 ch = store->open_collection(cid);
9982 }
9983
9984 // we want to extend the life-time of all huge paged-backed
9985 // bufferlists to validate the behaviour on pool exhaustion.
9986 bufferlist bl_1_huge, bl_2_huge, bl_3_plain;
9987
9988 cout << "Read object 1st time" << std::endl;
9989 {
9990 const auto r = store->read(ch, hoid, 0, HUGE_BUFFER_SIZE, bl_1_huge);
9991 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE), r);
9992 ASSERT_TRUE(bl_eq(bl, bl_1_huge));
9993 ASSERT_EQ(bl_1_huge.get_num_buffers(), 1);
9994 ASSERT_TRUE(is_hugepaged(bl_1_huge.front()));
9995 }
9996
9997 cout << "Read object 2nd time" << std::endl;
9998 {
9999 const auto r = store->read(ch, hoid, 0, HUGE_BUFFER_SIZE, bl_2_huge);
10000 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE), r);
10001 ASSERT_TRUE(bl_eq(bl, bl_2_huge));
10002 ASSERT_EQ(bl_2_huge.get_num_buffers(), 1);
10003 ASSERT_TRUE(is_hugepaged(bl_2_huge.front()));
10004 }
10005
10006 cout << "Read object 3rd time" << std::endl;
10007 {
10008 const auto r = store->read(ch, hoid, 0, HUGE_BUFFER_SIZE, bl_3_plain);
10009 ASSERT_EQ(static_cast<int>(HUGE_BUFFER_SIZE), r);
10010 ASSERT_TRUE(bl_eq(bl, bl_3_plain));
10011 ASSERT_EQ(bl_3_plain.get_num_buffers(), 1);
10012 ASSERT_FALSE(is_hugepaged(bl_3_plain.front()));
10013 }
10014 }
10015
10016 TEST_P(StoreTest, SpuriousReadErrorTest) {
10017 if (string(GetParam()) != "bluestore")
10018 return;
10019
10020 int r;
10021 auto logger = store->get_perf_counters();
10022 coll_t cid;
10023 auto ch = store->create_new_collection(cid);
10024 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
10025 {
10026 ObjectStore::Transaction t;
10027 t.create_collection(cid, 0);
10028 cerr << "Creating collection " << cid << std::endl;
10029 r = queue_transaction(store, ch, std::move(t));
10030 ASSERT_EQ(r, 0);
10031 }
10032 bufferlist test_data;
10033 bufferptr ap(0x2000);
10034 memset(ap.c_str(), 'a', 0x2000);
10035 test_data.append(ap);
10036 {
10037 ObjectStore::Transaction t;
10038 t.write(cid, hoid, 0, 0x2000, test_data);
10039 r = queue_transaction(store, ch, std::move(t));
10040 ASSERT_EQ(r, 0);
10041 // force cache clear
10042 EXPECT_EQ(store->umount(), 0);
10043 EXPECT_EQ(store->mount(), 0);
10044 }
10045 ch = store->open_collection(cid);
10046
10047 cerr << "Injecting CRC error with no retry, expecting EIO" << std::endl;
10048 SetVal(g_conf(), "bluestore_retry_disk_reads", "0");
10049 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "1");
10050 g_ceph_context->_conf.apply_changes(nullptr);
10051 {
10052 bufferlist in;
10053 r = store->read(ch, hoid, 0, 0x2000, in, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
10054 ASSERT_EQ(-EIO, r);
10055 ASSERT_EQ(logger->get(l_bluestore_read_eio), 1u);
10056 ASSERT_EQ(logger->get(l_bluestore_reads_with_retries), 0u);
10057 }
10058
10059 cerr << "Injecting CRC error with retries, expecting success after several retries" << std::endl;
10060 SetVal(g_conf(), "bluestore_retry_disk_reads", "255");
10061 SetVal(g_conf(), "bluestore_debug_inject_csum_err_probability", "0.8");
10062 /**
10063 * Probabilistic test: 25 reads, each has a 80% chance of failing with 255 retries
10064 * Probability of at least one retried read: 1 - (0.2 ** 25) = 100% - 3e-18
10065 * Probability of a random test failure: 1 - ((1 - (0.8 ** 255)) ** 25) ~= 5e-24
10066 */
10067 g_ceph_context->_conf.apply_changes(nullptr);
10068 {
10069 for (int i = 0; i < 25; ++i) {
10070 bufferlist in;
10071 r = store->read(ch, hoid, 0, 0x2000, in, CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
10072 ASSERT_EQ(0x2000, r);
10073 ASSERT_TRUE(bl_eq(test_data, in));
10074 }
10075 ASSERT_GE(logger->get(l_bluestore_reads_with_retries), 1u);
10076 }
10077 }
10078
10079 TEST_P(StoreTest, mergeRegionTest) {
10080 if (string(GetParam()) != "bluestore")
10081 return;
10082
10083 SetVal(g_conf(), "bluestore_fsck_on_mount", "true");
10084 SetVal(g_conf(), "bluestore_fsck_on_umount", "true");
10085 SetVal(g_conf(), "bdev_debug_inflight_ios", "true");
10086 g_ceph_context->_conf.apply_changes(nullptr);
10087
10088 uint32_t chunk_size = g_ceph_context->_conf->bdev_block_size;
10089 int r = -1;
10090 coll_t cid;
10091 ghobject_t hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP)));
10092 auto ch = store->create_new_collection(cid);
10093 {
10094 ObjectStore::Transaction t;
10095 t.create_collection(cid, 0);
10096 r = queue_transaction(store, ch, std::move(t));
10097 ASSERT_EQ(r, 0);
10098 }
10099 {
10100 ObjectStore::Transaction t;
10101 t.touch(cid, hoid);
10102 cerr << "Creating object " << hoid << std::endl;
10103 r = queue_transaction(store, ch, std::move(t));
10104 ASSERT_EQ(r, 0);
10105 }
10106 bufferlist bl5;
10107 bl5.append("abcde");
10108 uint64_t offset = 0;
10109 { // 1. same region
10110 ObjectStore::Transaction t;
10111 t.write(cid, hoid, offset, 5, bl5);
10112 t.write(cid, hoid, 0xa + offset, 5, bl5);
10113 t.write(cid, hoid, 0x14 + offset, 5, bl5);
10114 r = queue_transaction(store, ch, std::move(t));
10115 ASSERT_EQ(r, 0);
10116 }
10117 { // 2. adjacent regions
10118 ObjectStore::Transaction t;
10119 offset = chunk_size;
10120 t.write(cid, hoid, offset, 5, bl5);
10121 t.write(cid, hoid, offset + chunk_size + 3, 5, bl5);
10122 r = queue_transaction(store, ch, std::move(t));
10123 ASSERT_EQ(r, 0);
10124 }
10125 { // 3. front merge
10126 ObjectStore::Transaction t;
10127 offset = chunk_size * 2;
10128 t.write(cid, hoid, offset, 5, bl5);
10129 t.write(cid, hoid, offset + chunk_size - 2, 5, bl5);
10130 r = queue_transaction(store, ch, std::move(t));
10131 ASSERT_EQ(r, 0);
10132 }
10133 { // 4. back merge
10134 ObjectStore::Transaction t;
10135 bufferlist blc2;
10136 blc2.append_zero(chunk_size + 2);
10137
10138 offset = chunk_size * 3;
10139 t.write(cid, hoid, offset, chunk_size + 2, blc2);
10140 t.write(cid, hoid, offset + chunk_size + 3, 5, bl5);
10141 r = queue_transaction(store, ch, std::move(t));
10142 ASSERT_EQ(r, 0);
10143 }
10144 { // 5. overlapping
10145 ObjectStore::Transaction t;
10146 uint64_t final_len = 0;
10147 offset = chunk_size * 10;
10148 bufferlist bl2c2;
10149 bl2c2.append_zero(chunk_size * 2);
10150 t.write(cid, hoid, offset + chunk_size * 3 - 3, chunk_size * 2, bl2c2);
10151 bl2c2.append_zero(2);
10152 t.write(cid, hoid, offset + chunk_size - 2, chunk_size * 2 + 2, bl2c2);
10153 r = queue_transaction(store, ch, std::move(t));
10154 ASSERT_EQ(r, 0);
10155
10156 final_len = (offset + chunk_size * 3 - 3) + (chunk_size * 2);
10157 bufferlist bl;
10158 r = store->read(ch, hoid, 0, final_len, bl);
10159 ASSERT_EQ(final_len, static_cast<uint64_t>(r));
10160 }
10161 }
10162
10163 TEST_P(StoreTest, FixSMRWritePointer) {
10164 if(string(GetParam()) != "bluestore")
10165 return;
10166 if (!smr)
10167 return;
10168 int r = store->umount();
10169 ASSERT_EQ(0, r);
10170
10171 // copied from StoreTestFixture
10172 std::string path = GetParam() + ".test_temp_dir"s;
10173
10174 std::string p = path + "/block";
10175 BlockDevice* bdev = BlockDevice::create(g_ceph_context, p, nullptr, nullptr, nullptr, nullptr);
10176 r = bdev->open(p);
10177 ASSERT_EQ(0, r);
10178 ASSERT_EQ(true, bdev->is_smr());
10179
10180 std::vector<uint64_t> wp = bdev->get_zones();
10181 uint64_t first_seq_zone = bdev->get_conventional_region_size() / bdev->get_zone_size();
10182
10183 IOContext ioc(g_ceph_context, NULL, true);
10184 bufferlist bl;
10185 bl.append(std::string(1024 * 1024, 'x'));
10186 r = bdev->aio_write(wp[first_seq_zone], bl, &ioc, false);
10187 ASSERT_EQ(0, r);
10188 bdev->aio_submit(&ioc);
10189 ioc.aio_wait();
10190 bdev->close();
10191 delete bdev;
10192
10193 r = store->mount();
10194 ASSERT_EQ(0, r);
10195 }
10196
10197
10198 TEST_P(StoreTestSpecificAUSize, BluestoreEnforceHWSettingsHdd) {
10199 if (string(GetParam()) != "bluestore")
10200 return;
10201
10202 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
10203 StartDeferred(0x1000);
10204
10205 int r;
10206 coll_t cid;
10207 ghobject_t hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP)));
10208 auto ch = store->create_new_collection(cid);
10209 {
10210 ObjectStore::Transaction t;
10211 t.create_collection(cid, 0);
10212 cerr << "Creating collection " << cid << std::endl;
10213 r = queue_transaction(store, ch, std::move(t));
10214 ASSERT_EQ(r, 0);
10215 }
10216 {
10217 ObjectStore::Transaction t;
10218 bufferlist bl, orig;
10219 string s(g_ceph_context->_conf->bluestore_max_blob_size_hdd, '0');
10220 bl.append(s);
10221 t.write(cid, hoid, 0, bl.length(), bl);
10222 cerr << "write" << std::endl;
10223 r = queue_transaction(store, ch, std::move(t));
10224 ASSERT_EQ(r, 0);
10225
10226 const PerfCounters* logger = store->get_perf_counters();
10227 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 1u);
10228 }
10229 }
10230
10231 TEST_P(StoreTestSpecificAUSize, BluestoreEnforceHWSettingsSsd) {
10232 if (string(GetParam()) != "bluestore")
10233 return;
10234
10235 SetVal(g_conf(), "bluestore_debug_enforce_settings", "ssd");
10236 StartDeferred(0x1000);
10237
10238 int r;
10239 coll_t cid;
10240 ghobject_t hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP)));
10241 auto ch = store->create_new_collection(cid);
10242 {
10243 ObjectStore::Transaction t;
10244 t.create_collection(cid, 0);
10245 cerr << "Creating collection " << cid << std::endl;
10246 r = queue_transaction(store, ch, std::move(t));
10247 ASSERT_EQ(r, 0);
10248 }
10249 {
10250 ObjectStore::Transaction t;
10251 bufferlist bl, orig;
10252 string s(g_ceph_context->_conf->bluestore_max_blob_size_ssd * 8, '0');
10253 bl.append(s);
10254 t.write(cid, hoid, 0, bl.length(), bl);
10255 cerr << "write" << std::endl;
10256 r = queue_transaction(store, ch, std::move(t));
10257 ASSERT_EQ(r, 0);
10258
10259 const PerfCounters* logger = store->get_perf_counters();
10260 ASSERT_EQ(logger->get(l_bluestore_write_big_blobs), 8u);
10261 }
10262 }
10263
10264 TEST_P(StoreTestSpecificAUSize, ReproNoBlobMultiTest) {
10265
10266 if(string(GetParam()) != "bluestore")
10267 return;
10268 if (smr) {
10269 cout << "SKIP (FIXME): bluestore gc does not seem to do the trick here" << std::endl;
10270 return;
10271 }
10272
10273 SetVal(g_conf(), "bluestore_block_db_create", "true");
10274 SetVal(g_conf(), "bluestore_block_db_size", "4294967296");
10275 SetVal(g_conf(), "bluestore_block_size", "12884901888");
10276 SetVal(g_conf(), "bluestore_max_blob_size", "524288");
10277
10278 g_conf().apply_changes(nullptr);
10279
10280 StartDeferred(65536);
10281
10282 int r;
10283 coll_t cid;
10284 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
10285 ghobject_t hoid2 = hoid;
10286 hoid2.hobj.snap = 1;
10287
10288 auto ch = store->create_new_collection(cid);
10289 {
10290 ObjectStore::Transaction t;
10291 t.create_collection(cid, 0);
10292 cerr << "Creating collection " << cid << std::endl;
10293 r = queue_transaction(store, ch, std::move(t));
10294 ASSERT_EQ(r, 0);
10295 }
10296 {
10297 bool exists = store->exists(ch, hoid);
10298 ASSERT_TRUE(!exists);
10299
10300 ObjectStore::Transaction t;
10301 t.touch(cid, hoid);
10302 cerr << "Creating object " << hoid << std::endl;
10303 r = queue_transaction(store, ch, std::move(t));
10304 ASSERT_EQ(r, 0);
10305
10306 exists = store->exists(ch, hoid);
10307 ASSERT_EQ(true, exists);
10308 }
10309 {
10310 uint64_t offs = 0;
10311 bufferlist bl;
10312 const int size = 0x100;
10313 bufferptr ap(size);
10314 memset(ap.c_str(), 'a', size);
10315 bl.append(ap);
10316 int i = 0;
10317 uint64_t blob_size = 524288;
10318 uint64_t total = 0;
10319 for (i = 0; i <= 512; i++) {
10320 offs = 0 + i * size;
10321 ObjectStore::Transaction t;
10322 ghobject_t hoid2 = hoid;
10323 hoid2.hobj.snap = i + 1;
10324 while (offs < 128 * 1024 * 1024) {
10325
10326 t.write(cid, hoid, offs, ap.length(), bl);
10327 offs += blob_size;
10328 total += ap.length();
10329 }
10330 t.clone(cid, hoid, hoid2);
10331 r = queue_transaction(store, ch, std::move(t));
10332 ASSERT_EQ(r, 0);
10333 }
10334 cerr << "Total written = " << total << std::endl;
10335 }
10336 {
10337 cerr << "Finalizing" << std::endl;
10338 const PerfCounters* logger = store->get_perf_counters();
10339 ASSERT_GE(logger->get(l_bluestore_gc_merged), 1024*1024*1024);
10340 }
10341 }
10342
10343 void doManySetAttr(ObjectStore* store,
10344 std::function<void(ObjectStore*)> do_check_fn)
10345 {
10346 MixedGenerator gen(447);
10347 gen_type rng(time(NULL));
10348 coll_t cid(spg_t(pg_t(0, 447), shard_id_t::NO_SHARD));
10349
10350 SyntheticWorkloadState test_obj(store, &gen, &rng, cid, 0, 0, 0);
10351 test_obj.init();
10352 size_t object_count = 256;
10353 for (size_t i = 0; i < object_count; ++i) {
10354 if (!(i % 10)) cerr << "seeding object " << i << std::endl;
10355 test_obj.touch();
10356 }
10357 for (size_t i = 0; i < object_count; ++i) {
10358 if (!(i % 100)) {
10359 cerr << "Op " << i << std::endl;
10360 test_obj.print_internal_state();
10361 }
10362 test_obj.set_fixed_attrs(1024, 64, 4096); // 1024 attributes, 64 bytes name and 4K value
10363 }
10364 test_obj.wait_for_done();
10365
10366 std::cout << "done" << std::endl;
10367 do_check_fn(store);
10368 AdminSocket* admin_socket = g_ceph_context->get_admin_socket();
10369 ceph_assert(admin_socket);
10370
10371 ceph::bufferlist in, out;
10372 ostringstream err;
10373
10374 auto r = admin_socket->execute_command(
10375 { "{\"prefix\": \"bluefs stats\"}" },
10376 in, err, &out);
10377 if (r != 0) {
10378 cerr << "failure querying: " << cpp_strerror(r) << std::endl;
10379 } else {
10380 std::cout << std::string(out.c_str(), out.length()) << std::endl;
10381 }
10382 test_obj.shutdown();
10383 }
10384
10385 TEST_P(StoreTestSpecificAUSize, SpilloverTest) {
10386 if (string(GetParam()) != "bluestore")
10387 return;
10388 if (smr) {
10389 cout << "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl;
10390 return;
10391 }
10392
10393 SetVal(g_conf(), "bluestore_block_db_create", "true");
10394 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10395 SetVal(g_conf(), "bluestore_volume_selection_policy", "rocksdb_original");
10396 // original RocksDB settings used before https://github.com/ceph/ceph/pull/47221/
10397 // which enable BlueFS spillover.
10398 SetVal(g_conf(), "bluestore_rocksdb_options",
10399 "compression=kNoCompression,max_write_buffer_number=4,"
10400 "min_write_buffer_number_to_merge=1,recycle_log_file_num=4,"
10401 "write_buffer_size=268435456,writable_file_max_buffer_size=0,"
10402 "compaction_readahead_size=2097152,max_background_compactions=2,"
10403 "max_total_wal_size=1073741824");
10404
10405 g_conf().apply_changes(nullptr);
10406
10407 StartDeferred(65536);
10408 doManySetAttr(store.get(),
10409 [&](ObjectStore* _store) {
10410
10411 BlueStore* bstore = dynamic_cast<BlueStore*> (_store);
10412 ceph_assert(bstore);
10413 bstore->compact();
10414 const PerfCounters* logger = bstore->get_bluefs_perf_counters();
10415 //experimentally it was discovered that this case results in 400+MB spillover
10416 //using lower 300MB threshold just to be safe enough
10417 std::cout << "DB used:" << logger->get(l_bluefs_db_used_bytes) << std::endl;
10418 std::cout << "SLOW used:" << logger->get(l_bluefs_slow_used_bytes) << std::endl;
10419 ASSERT_GE(logger->get(l_bluefs_slow_used_bytes), 16 * 1024 * 1024);
10420
10421 struct store_statfs_t statfs;
10422 osd_alert_list_t alerts;
10423 int r = store->statfs(&statfs, &alerts);
10424 ASSERT_EQ(r, 0);
10425 ASSERT_EQ(alerts.count("BLUEFS_SPILLOVER"), 1);
10426 std::cout << "spillover_alert:" << alerts.find("BLUEFS_SPILLOVER")->second
10427 << std::endl;
10428 }
10429 );
10430 }
10431
10432 TEST_P(StoreTestSpecificAUSize, SpilloverFixedTest) {
10433 if (string(GetParam()) != "bluestore")
10434 return;
10435 if (smr) {
10436 cout << "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl;
10437 return;
10438 }
10439
10440 SetVal(g_conf(), "bluestore_block_db_create", "true");
10441 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10442 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
10443 SetVal(g_conf(), "bluestore_volume_selection_reserved", "1"); // just use non-zero to enable
10444
10445 g_conf().apply_changes(nullptr);
10446
10447 StartDeferred(65536);
10448 doManySetAttr(store.get(),
10449 [&](ObjectStore* _store) {
10450
10451 BlueStore* bstore = dynamic_cast<BlueStore*> (_store);
10452 ceph_assert(bstore);
10453 bstore->compact();
10454 const PerfCounters* logger = bstore->get_bluefs_perf_counters();
10455 ASSERT_EQ(0, logger->get(l_bluefs_slow_used_bytes));
10456 }
10457 );
10458 }
10459
10460 TEST_P(StoreTestSpecificAUSize, SpilloverFixed2Test) {
10461 if (string(GetParam()) != "bluestore")
10462 return;
10463 if (smr) {
10464 cout << "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl;
10465 return;
10466 }
10467
10468 SetVal(g_conf(), "bluestore_block_db_create", "true");
10469 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10470 SetVal(g_conf(), "bluestore_volume_selection_policy", "use_some_extra");
10471 //default 2.0 factor results in too high threshold, using less value
10472 // that results in less but still present spillover.
10473 SetVal(g_conf(), "bluestore_volume_selection_reserved_factor", "0.5");
10474
10475 g_conf().apply_changes(nullptr);
10476
10477 StartDeferred(65536);
10478 doManySetAttr(store.get(),
10479 [&](ObjectStore* _store) {
10480
10481 BlueStore* bstore = dynamic_cast<BlueStore*> (_store);
10482 ceph_assert(bstore);
10483 bstore->compact();
10484 const PerfCounters* logger = bstore->get_bluefs_perf_counters();
10485 ASSERT_LE(logger->get(l_bluefs_slow_used_bytes), 300 * 1024 * 1024); // see SpilloverTest for 300MB choice rationale
10486 }
10487 );
10488 }
10489
10490 TEST_P(StoreTestSpecificAUSize, SpilloverFixed3Test) {
10491 if (string(GetParam()) != "bluestore")
10492 return;
10493 if (smr) {
10494 cout << "SKIP: (FIXME?) adjust me for smr at some point?" << std::endl;
10495 return;
10496 }
10497
10498 SetVal(g_conf(), "bluestore_block_db_create", "true");
10499 SetVal(g_conf(), "bluestore_block_db_size", "3221225472");
10500 SetVal(g_conf(), "bluestore_volume_selection_policy", "fit_to_fast");
10501
10502 g_conf().apply_changes(nullptr);
10503
10504 StartDeferred(65536);
10505 doManySetAttr(store.get(),
10506 [&](ObjectStore* _store) {
10507
10508 BlueStore* bstore = dynamic_cast<BlueStore*> (_store);
10509 ceph_assert(bstore);
10510 bstore->compact();
10511 const PerfCounters* logger = bstore->get_bluefs_perf_counters();
10512 ASSERT_EQ(logger->get(l_bluefs_slow_used_bytes), 0); // reffering to SpilloverFixedTest
10513 }
10514 );
10515 }
10516
10517 TEST_P(StoreTestSpecificAUSize, Ticket45195Repro) {
10518 if (string(GetParam()) != "bluestore")
10519 return;
10520 if (smr) {
10521 return;
10522 }
10523
10524 SetVal(g_conf(), "bluestore_default_buffered_write", "true");
10525 SetVal(g_conf(), "bluestore_max_blob_size", "65536");
10526 SetVal(g_conf(), "bluestore_debug_enforce_settings", "hdd");
10527 SetVal(g_conf(), "bluestore_fsck_on_mount", "false");
10528 g_conf().apply_changes(nullptr);
10529
10530 StartDeferred(0x1000);
10531
10532 int r;
10533 coll_t cid;
10534 ghobject_t hoid(hobject_t(sobject_t("Object", CEPH_NOSNAP)));
10535 auto ch = store->create_new_collection(cid);
10536 {
10537 ObjectStore::Transaction t;
10538 t.create_collection(cid, 0);
10539 cerr << "Creating collection " << cid << std::endl;
10540 r = queue_transaction(store, ch, std::move(t));
10541 ASSERT_EQ(r, 0);
10542 }
10543 {
10544 size_t large_object_size = 1 * 1024 * 1024;
10545 size_t expected_write_size = 0x8000;
10546 ObjectStore::Transaction t;
10547 t.touch(cid, hoid);
10548 t.set_alloc_hint(cid, hoid, large_object_size, expected_write_size,
10549 CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ |
10550 CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY);
10551 r = queue_transaction(store, ch, std::move(t));
10552 ASSERT_EQ(r, 0);
10553 }
10554 {
10555 ObjectStore::Transaction t;
10556 bufferlist bl, orig;
10557 string s(0xc000, '0');
10558 bl.append(s);
10559 t.write(cid, hoid, 0xb000, bl.length(), bl);
10560 r = queue_transaction(store, ch, std::move(t));
10561 ASSERT_EQ(r, 0);
10562 }
10563 {
10564 ObjectStore::Transaction t;
10565 bufferlist bl, orig;
10566 string s(0x10000, '1');
10567 bl.append(s);
10568 t.write(cid, hoid, 0x16000, bl.length(), bl);
10569 r = queue_transaction(store, ch, std::move(t));
10570 ASSERT_EQ(r, 0);
10571 }
10572 {
10573 ObjectStore::Transaction t;
10574 bufferlist bl, orig;
10575 string s(0x4000, '1');
10576 bl.append(s);
10577 t.write(cid, hoid, 0x1b000, bl.length(), bl);
10578 r = queue_transaction(store, ch, std::move(t));
10579 ASSERT_EQ(r, 0);
10580 }
10581 bufferlist bl;
10582 r = store->read(ch, hoid, 0xb000, 0xb000, bl);
10583 ASSERT_EQ(r, 0xb000);
10584
10585 store->umount();
10586 store->mount();
10587
10588 ch = store->open_collection(cid);
10589 {
10590 ObjectStore::Transaction t;
10591 bufferlist bl, orig;
10592 string s(0xf000, '3');
10593 bl.append(s);
10594 t.write(cid, hoid, 0xf000, bl.length(), bl);
10595 cerr << "write4" << std::endl;
10596 r = queue_transaction(store, ch, std::move(t));
10597 ASSERT_EQ(r, 0);
10598 }
10599
10600 r = store->read(ch, hoid, 0xb000, 0x10000, bl);
10601 ASSERT_EQ(r, 0x10000);
10602 }
10603
10604 TEST_P(StoreTestOmapUpgrade, WithOmapHeader) {
10605 if (string(GetParam()) != "bluestore")
10606 return;
10607
10608 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10609 g_conf().apply_changes(nullptr);
10610
10611 StartDeferred();
10612 int64_t poolid = 11;
10613 coll_t cid(spg_t(pg_t(1, poolid), shard_id_t::NO_SHARD));
10614 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, poolid, ""));
10615 auto ch = store->create_new_collection(cid);
10616 int r;
10617 {
10618 ObjectStore::Transaction t;
10619 t.create_collection(cid, 0);
10620 r = queue_transaction(store, ch, std::move(t));
10621 ASSERT_EQ(r, 0);
10622 }
10623
10624 map<string, bufferlist> attrs;
10625 bufferlist expected_header;
10626 expected_header.append("this is a header");
10627 {
10628 ObjectStore::Transaction t;
10629 t.touch(cid, hoid);
10630 bufferlist header;
10631 header.append(expected_header);
10632 t.omap_setheader(cid, hoid, header);
10633 map<string, bufferlist> start_set;
10634 bufferlist bl;
10635 bl.append(string("value"));
10636 start_set.emplace(string("key1"), bl);
10637 t.omap_setkeys(cid, hoid, start_set);
10638 r = queue_transaction(store, ch, std::move(t));
10639 }
10640 {
10641 map<string,bufferlist> res;
10642 bufferlist h;
10643 r = store->omap_get(ch, hoid, &h, &res);
10644 ASSERT_EQ(r, 0);
10645 ASSERT_TRUE(bl_eq(h, expected_header));
10646 ASSERT_EQ(res.size(), 1);
10647 ASSERT_EQ(res.begin()->first, "key1");
10648 }
10649 store->umount();
10650 ASSERT_EQ(store->fsck(false), 0);
10651 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10652 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10653 g_conf().apply_changes(nullptr);
10654 ASSERT_EQ(store->fsck(false), 2);
10655 ASSERT_EQ(store->quick_fix(), 0);
10656 store->mount();
10657 ch = store->open_collection(cid);
10658 {
10659 map<string,bufferlist> res;
10660 bufferlist h;
10661 r = store->omap_get(ch, hoid, &h, &res);
10662 ASSERT_EQ(r, 0);
10663 ASSERT_EQ(res.size(), 1);
10664 ASSERT_EQ(res.begin()->first, "key1");
10665 }
10666 {
10667 ObjectStore::Transaction t;
10668 t.remove(cid, hoid);
10669 t.remove_collection(cid);
10670 r = queue_transaction(store, ch, std::move(t));
10671 ASSERT_EQ(r, 0);
10672 }
10673 }
10674
10675 TEST_P(StoreTestSpecificAUSize, BluefsWriteInSingleDiskEnvTest) {
10676 if (string(GetParam()) != "bluestore")
10677 return;
10678
10679 g_conf().apply_changes(nullptr);
10680
10681 StartDeferred(0x1000);
10682
10683 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
10684 ceph_assert(bstore);
10685 bstore->inject_bluefs_file("db.slow", "store_test_injection_slow", 1 << 20ul);
10686 bstore->inject_bluefs_file("db.wal", "store_test_injection_wal", 1 << 20ul);
10687 bstore->inject_bluefs_file("db", "store_test_injection_wal", 1 << 20ul);
10688
10689 AdminSocket* admin_socket = g_ceph_context->get_admin_socket();
10690 ceph_assert(admin_socket);
10691
10692 ceph::bufferlist in, out;
10693 ostringstream err;
10694 auto r = admin_socket->execute_command(
10695 { "{\"prefix\": \"bluefs stats\"}" },
10696 in, err, &out);
10697 if (r != 0) {
10698 cerr << "failure querying: " << cpp_strerror(r) << std::endl;
10699 } else {
10700 std::cout << std::string(out.c_str(), out.length()) << std::endl;
10701 }
10702 }
10703
10704 TEST_P(StoreTestSpecificAUSize, BluefsWriteInNoWalDiskEnvTest) {
10705 if (string(GetParam()) != "bluestore")
10706 return;
10707
10708 SetVal(g_conf(), "bluestore_block_db_path", "db");
10709 SetVal(g_conf(), "bluestore_block_db_size", stringify(1ull << 31).c_str());
10710 SetVal(g_conf(), "bluestore_block_db_create", "true");
10711
10712 g_conf().apply_changes(nullptr);
10713
10714 StartDeferred(0x1000);
10715
10716 BlueStore* bstore = dynamic_cast<BlueStore*> (store.get());
10717 ceph_assert(bstore);
10718 bstore->inject_bluefs_file("db.slow", "store_test_injection_slow", 1 << 20ul);
10719 bstore->inject_bluefs_file("db.wal", "store_test_injection_wal", 1 << 20ul);
10720 bstore->inject_bluefs_file("db", "store_test_injection_wal", 1 << 20ul);
10721
10722 AdminSocket* admin_socket = g_ceph_context->get_admin_socket();
10723 ceph_assert(admin_socket);
10724
10725 ceph::bufferlist in, out;
10726 ostringstream err;
10727 auto r = admin_socket->execute_command(
10728 { "{\"prefix\": \"bluefs stats\"}" },
10729 in, err, &out);
10730 if (r != 0) {
10731 cerr << "failure querying: " << cpp_strerror(r) << std::endl;
10732 }
10733 else {
10734 std::cout << std::string(out.c_str(), out.length()) << std::endl;
10735 }
10736 }
10737
10738 TEST_P(StoreTestOmapUpgrade, NoOmapHeader) {
10739 if (string(GetParam()) != "bluestore")
10740 return;
10741
10742 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10743 g_conf().apply_changes(nullptr);
10744
10745 StartDeferred();
10746 int64_t poolid = 11;
10747 coll_t cid(spg_t(pg_t(1, poolid), shard_id_t::NO_SHARD));
10748 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, poolid, ""));
10749 auto ch = store->create_new_collection(cid);
10750 int r;
10751 {
10752 ObjectStore::Transaction t;
10753 t.create_collection(cid, 0);
10754 r = queue_transaction(store, ch, std::move(t));
10755 ASSERT_EQ(r, 0);
10756 }
10757
10758 map<string, bufferlist> attrs;
10759 {
10760 ObjectStore::Transaction t;
10761 t.touch(cid, hoid);
10762 map<string, bufferlist> start_set;
10763 bufferlist bl;
10764 bl.append(string("value"));
10765 start_set.emplace(string("key1"), bl);
10766 t.omap_setkeys(cid, hoid, start_set);
10767 r = queue_transaction(store, ch, std::move(t));
10768 }
10769 {
10770 map<string,bufferlist> res;
10771 bufferlist h;
10772 r = store->omap_get(ch, hoid, &h, &res);
10773 ASSERT_EQ(r, 0);
10774 ASSERT_EQ(h.length(), 0);
10775 ASSERT_EQ(res.size(), 1);
10776 ASSERT_EQ(res.begin()->first, "key1");
10777 }
10778 store->umount();
10779 ASSERT_EQ(store->fsck(false), 0);
10780 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10781 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10782 g_conf().apply_changes(nullptr);
10783 ASSERT_EQ(store->fsck(false), 2);
10784 ASSERT_EQ(store->quick_fix(), 0);
10785 store->mount();
10786 ch = store->open_collection(cid);
10787 {
10788 map<string,bufferlist> res;
10789 bufferlist h;
10790 r = store->omap_get(ch, hoid, &h, &res);
10791 ASSERT_EQ(r, 0);
10792 ASSERT_EQ(res.size(), 1);
10793 ASSERT_EQ(res.begin()->first, "key1");
10794 }
10795 {
10796 ObjectStore::Transaction t;
10797 t.remove(cid, hoid);
10798 t.remove_collection(cid);
10799 r = queue_transaction(store, ch, std::move(t));
10800 ASSERT_EQ(r, 0);
10801 }
10802 }
10803
10804 TEST_P(StoreTestOmapUpgrade, LargeLegacyToPG) {
10805 if (string(GetParam()) != "bluestore")
10806 return;
10807
10808 SetVal(g_conf(), "bluestore_debug_legacy_omap", "true");
10809 g_conf().apply_changes(nullptr);
10810
10811 int64_t poolid;
10812 coll_t cid;
10813 ghobject_t hoid;
10814 ObjectStore::CollectionHandle ch;
10815 StartDeferred();
10816 poolid = 11;
10817 cid = coll_t(spg_t(pg_t(1, poolid), shard_id_t::NO_SHARD));
10818 ch = store->create_new_collection(cid);
10819 int r;
10820 {
10821 ObjectStore::Transaction t;
10822 t.create_collection(cid, 0);
10823 r = queue_transaction(store, ch, std::move(t));
10824 ASSERT_EQ(r, 0);
10825 }
10826 //ASSERT_EQ(false, g_conf().get_val<bool>("bluestore_debug_inject_upgrade_bug53062"));
10827 map<string, bufferlist> attrs;
10828 bufferlist expected_header;
10829 expected_header.append("this is a header");
10830
10831 size_t object_count = 1000;
10832 make_omap_data(object_count, poolid, cid);
10833 //checking just written data
10834 check_omap_data(object_count, poolid, cid);
10835
10836 store->umount();
10837 ASSERT_EQ(store->fsck(false), 0);
10838 SetVal(g_conf(), "bluestore_debug_legacy_omap", "false");
10839 SetVal(g_conf(), "bluestore_fsck_error_on_no_per_pool_omap", "true");
10840 g_conf().apply_changes(nullptr);
10841 ASSERT_EQ(store->fsck(false), 1001);
10842 ASSERT_EQ(store->quick_fix(), 0);
10843 store->mount();
10844 ch = store->open_collection(cid);
10845
10846 //checking quick_fix() data
10847 check_omap_data(object_count, poolid, cid);
10848
10849 {
10850 ObjectStore::Transaction t;
10851 for (size_t o = 0; o < object_count; o++)
10852 {
10853 std::string oid = generate_monotonic_name(object_count, o, 3.71, 0.5);
10854 ghobject_t hoid(hobject_t(oid, "", CEPH_NOSNAP, 0, poolid, ""));
10855 t.remove(cid, hoid);
10856 }
10857 t.remove_collection(cid);
10858 r = queue_transaction(store, ch, std::move(t));
10859 ASSERT_EQ(r, 0);
10860 }
10861 }
10862
10863 #endif // WITH_BLUESTORE
10864
10865 int main(int argc, char **argv) {
10866 auto args = argv_to_vec(argc, argv);
10867 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
10868 CODE_ENVIRONMENT_UTILITY,
10869 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
10870 common_init_finish(g_ceph_context);
10871
10872 for (auto& i : args) {
10873 if (i == "--smr"s) {
10874 #if defined(HAVE_LIBZBD)
10875 derr << "Adjusting tests for smr mode." << dendl;
10876 smr = true;
10877 #else
10878 derr << "smr mode selected, but support not compiled in" << dendl;
10879 return 1;
10880 #endif
10881 }
10882 }
10883
10884 // make sure we can adjust any config settings
10885 g_ceph_context->_conf._clear_safe_to_start_threads();
10886
10887 g_ceph_context->_conf.set_val_or_die("osd_journal_size", "400");
10888 g_ceph_context->_conf.set_val_or_die("filestore_index_retry_probability", "0.5");
10889 g_ceph_context->_conf.set_val_or_die("filestore_op_thread_timeout", "1000");
10890 g_ceph_context->_conf.set_val_or_die("filestore_op_thread_suicide_timeout", "10000");
10891 //g_ceph_context->_conf.set_val_or_die("filestore_fiemap", "true");
10892 g_ceph_context->_conf.set_val_or_die("bluestore_fsck_on_mkfs", "false");
10893 g_ceph_context->_conf.set_val_or_die("bluestore_fsck_on_mount", "false");
10894 g_ceph_context->_conf.set_val_or_die("bluestore_fsck_on_umount", "false");
10895 g_ceph_context->_conf.set_val_or_die("bluestore_debug_small_allocations", "4");
10896 g_ceph_context->_conf.set_val_or_die("bluestore_debug_freelist", "true");
10897 g_ceph_context->_conf.set_val_or_die("bluestore_clone_cow", "true");
10898 g_ceph_context->_conf.set_val_or_die("bluestore_max_alloc_size", "196608");
10899 // set small cache sizes so we see trimming during Synthetic tests
10900 g_ceph_context->_conf.set_val_or_die("bluestore_cache_size_hdd", "4000000");
10901 g_ceph_context->_conf.set_val_or_die("bluestore_cache_size_ssd", "4000000");
10902 g_ceph_context->_conf.set_val_or_die(
10903 "bluestore_debug_inject_allocation_from_file_failure", "0.66");
10904
10905 // very short *_max prealloc so that we fall back to async submits
10906 g_ceph_context->_conf.set_val_or_die("bluestore_blobid_prealloc", "10");
10907 g_ceph_context->_conf.set_val_or_die("bluestore_nid_prealloc", "10");
10908 g_ceph_context->_conf.set_val_or_die("bluestore_debug_randomize_serial_transaction",
10909 "10");
10910
10911 g_ceph_context->_conf.set_val_or_die("bdev_debug_aio", "true");
10912
10913 // specify device size
10914 g_ceph_context->_conf.set_val_or_die("bluestore_block_size",
10915 stringify(DEF_STORE_TEST_BLOCKDEV_SIZE));
10916
10917 g_ceph_context->_conf.set_val_or_die(
10918 "enable_experimental_unrecoverable_data_corrupting_features", "*");
10919 g_ceph_context->_conf.apply_changes(nullptr);
10920
10921 ::testing::InitGoogleTest(&argc, argv);
10922 return RUN_ALL_TESTS();
10923 }
10924
10925 /*
10926 * Local Variables:
10927 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
10928 * ./ceph_test_objectstore \
10929 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20
10930 * "
10931 * End:
10932 */