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