]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/objectstore/store_test.cc
update sources to v12.2.3
[ceph.git] / ceph / src / test / objectstore / store_test.cc
CommitLineData
7c673cae
FG
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(HAVE_LIBAIO)
30#include "os/bluestore/BlueStore.h"
31#endif
32#include "include/Context.h"
33#include "common/ceph_argparse.h"
34#include "global/global_init.h"
35#include "common/Mutex.h"
36#include "common/Cond.h"
37#include "common/errno.h"
38#include "include/stringify.h"
39#include "include/coredumpctl.h"
40
41#include "include/unordered_map.h"
42#include "store_test_fixture.h"
43
44
45typedef boost::mt11213b gen_type;
46
47#define dout_context g_ceph_context
48
49#if GTEST_HAS_PARAM_TEST
50
51static bool bl_eq(bufferlist& expected, bufferlist& actual)
52{
53 if (expected.contents_equal(actual))
54 return true;
55
56 unsigned first = 0;
57 if(expected.length() != actual.length()) {
58 cout << "--- buffer lengths mismatch " << std::hex
59 << "expected 0x" << expected.length() << " != actual 0x"
60 << actual.length() << std::dec << std::endl;
61 derr << "--- buffer lengths mismatch " << std::hex
62 << "expected 0x" << expected.length() << " != actual 0x"
63 << actual.length() << std::dec << dendl;
64 }
65 auto len = MIN(expected.length(), actual.length());
66 while ( first<len && expected[first] == actual[first])
67 ++first;
68 unsigned last = len;
69 while (last > 0 && expected[last-1] == actual[last-1])
70 --last;
71 if(len > 0) {
72 cout << "--- buffer mismatch between offset 0x" << std::hex << first
73 << " and 0x" << last << ", total 0x" << len << std::dec
74 << std::endl;
75 derr << "--- buffer mismatch between offset 0x" << std::hex << first
76 << " and 0x" << last << ", total 0x" << len << std::dec
77 << dendl;
78 cout << "--- expected:\n";
79 expected.hexdump(cout);
80 cout << "--- actual:\n";
81 actual.hexdump(cout);
82 }
83 return false;
84}
85
86
87
88template <typename T>
89int apply_transaction(
90 T &store,
91 ObjectStore::Sequencer *osr,
92 ObjectStore::Transaction &&t) {
93 if (rand() % 2) {
94 ObjectStore::Transaction t2;
95 t2.append(t);
96 return store->apply_transaction(osr, std::move(t2));
97 } else {
98 return store->apply_transaction(osr, std::move(t));
99 }
100}
101
102
103bool sorted(const vector<ghobject_t> &in) {
104 ghobject_t start;
105 for (vector<ghobject_t>::const_iterator i = in.begin();
106 i != in.end();
107 ++i) {
108 if (start > *i) {
109 cout << start << " should follow " << *i << std::endl;
110 return false;
111 }
112 start = *i;
113 }
114 return true;
115}
116
117class StoreTest : public StoreTestFixture,
118 public ::testing::WithParamInterface<const char*> {
119public:
120 StoreTest()
121 : StoreTestFixture(GetParam())
122 {}
123};
124
125class StoreTestDeferredSetup : public StoreTest {
126 void SetUp() override {
127 //do nothing
128 }
129
130protected:
131 void DeferredSetup() {
132 StoreTest::SetUp();
133 }
134
135public:
136};
137
138class StoreTestSpecificAUSize : public StoreTestDeferredSetup {
139
140public:
141 typedef
142 std::function<void(
143 boost::scoped_ptr<ObjectStore>& store,
144 uint64_t num_ops,
145 uint64_t max_obj,
146 uint64_t max_wr,
147 uint64_t align)> MatrixTest;
148
149 void StartDeferred(size_t min_alloc_size) {
150 g_conf->set_val("bluestore_min_alloc_size", stringify(min_alloc_size));
151 DeferredSetup();
152 }
153
154 void TearDown() override {
155 g_conf->set_val("bluestore_min_alloc_size", "0");
156 StoreTestDeferredSetup::TearDown();
157 }
158
159private:
160 // bluestore matrix testing
161 uint64_t max_write = 40 * 1024;
162 uint64_t max_size = 400 * 1024;
163 uint64_t alignment = 0;
164 uint64_t num_ops = 10000;
165
166protected:
167 string matrix_get(const char *k) {
168 if (string(k) == "max_write") {
169 return stringify(max_write);
170 } else if (string(k) == "max_size") {
171 return stringify(max_size);
172 } else if (string(k) == "alignment") {
173 return stringify(alignment);
174 } else if (string(k) == "num_ops") {
175 return stringify(num_ops);
176 } else {
177 char *buf;
178 g_conf->get_val(k, &buf, -1);
179 string v = buf;
180 free(buf);
181 return v;
182 }
183 }
184
185 void matrix_set(const char *k, const char *v) {
186 if (string(k) == "max_write") {
187 max_write = atoll(v);
188 } else if (string(k) == "max_size") {
189 max_size = atoll(v);
190 } else if (string(k) == "alignment") {
191 alignment = atoll(v);
192 } else if (string(k) == "num_ops") {
193 num_ops = atoll(v);
194 } else {
195 g_conf->set_val(k, v);
196 }
197 }
198
199 void do_matrix_choose(const char *matrix[][10],
200 int i, int pos, int num,
201 boost::scoped_ptr<ObjectStore>& store,
202 MatrixTest fn) {
203 if (matrix[i][0]) {
204 int count;
205 for (count = 0; matrix[i][count+1]; ++count) ;
206 for (int j = 1; matrix[i][j]; ++j) {
207 matrix_set(matrix[i][0], matrix[i][j]);
208 do_matrix_choose(matrix,
209 i + 1,
210 pos * count + j - 1,
211 num * count,
212 store,
213 fn);
214 }
215 } else {
216 cout << "---------------------- " << (pos + 1) << " / " << num
217 << " ----------------------" << std::endl;
218 for (unsigned k=0; matrix[k][0]; ++k) {
219 cout << " " << matrix[k][0] << " = " << matrix_get(matrix[k][0])
220 << std::endl;
221 }
222 g_ceph_context->_conf->apply_changes(NULL);
223 fn(store, num_ops, max_size, max_write, alignment);
224 }
225 }
226
227 void do_matrix(const char *matrix[][10],
228 boost::scoped_ptr<ObjectStore>& store,
229 MatrixTest fn) {
230 map<string,string> old;
231 for (unsigned i=0; matrix[i][0]; ++i) {
232 old[matrix[i][0]] = matrix_get(matrix[i][0]);
233 }
234 cout << "saved config options " << old << std::endl;
235
236 if (strcmp(matrix[0][0], "bluestore_min_alloc_size") == 0) {
237 int count;
238 for (count = 0; matrix[0][count+1]; ++count) ;
239 for (size_t j = 1; matrix[0][j]; ++j) {
240 if (j > 1) {
241 TearDown();
242 }
243 StartDeferred(strtoll(matrix[0][j], NULL, 10));
244 do_matrix_choose(matrix, 1, j - 1, count, store, fn);
245 }
246 } else {
247 StartDeferred(0);
248 do_matrix_choose(matrix, 0, 0, 1, store, fn);
249 }
250
251 cout << "restoring config options " << old << std::endl;
252 for (auto p : old) {
253 cout << " " << p.first << " = " << p.second << std::endl;
254 matrix_set(p.first.c_str(), p.second.c_str());
255 }
256 g_ceph_context->_conf->apply_changes(NULL);
257 }
258
259};
260
261TEST_P(StoreTest, collect_metadata) {
262 map<string,string> pm;
263 store->collect_metadata(&pm);
264 if (GetParam() == string("filestore")) {
265 ASSERT_NE(pm.count("filestore_backend"), 0u);
266 ASSERT_NE(pm.count("filestore_f_type"), 0u);
267 ASSERT_NE(pm.count("backend_filestore_partition_path"), 0u);
268 ASSERT_NE(pm.count("backend_filestore_dev_node"), 0u);
269 }
270}
271
272TEST_P(StoreTest, Trivial) {
273}
274
275TEST_P(StoreTest, TrivialRemount) {
276 int r = store->umount();
277 ASSERT_EQ(0, r);
278 r = store->mount();
279 ASSERT_EQ(0, r);
280}
281
282TEST_P(StoreTest, SimpleRemount) {
283 ObjectStore::Sequencer osr("test");
284 coll_t cid;
285 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
286 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
287 bufferlist bl;
288 bl.append("1234512345");
289 int r;
290 {
291 cerr << "create collection + write" << std::endl;
292 ObjectStore::Transaction t;
293 t.create_collection(cid, 0);
294 t.write(cid, hoid, 0, bl.length(), bl);
295 r = apply_transaction(store, &osr, std::move(t));
296 ASSERT_EQ(r, 0);
297 }
298 r = store->umount();
299 ASSERT_EQ(0, r);
300 r = store->mount();
301 ASSERT_EQ(0, r);
302 {
303 ObjectStore::Transaction t;
304 t.write(cid, hoid2, 0, bl.length(), bl);
305 r = apply_transaction(store, &osr, std::move(t));
306 ASSERT_EQ(r, 0);
307 }
308 {
309 ObjectStore::Transaction t;
310 t.remove(cid, hoid);
311 t.remove(cid, hoid2);
312 t.remove_collection(cid);
313 cerr << "remove collection" << std::endl;
314 r = apply_transaction(store, &osr, std::move(t));
315 ASSERT_EQ(r, 0);
316 }
317 r = store->umount();
318 ASSERT_EQ(0, r);
319 r = store->mount();
320 ASSERT_EQ(0, r);
321 {
322 ObjectStore::Transaction t;
323 t.create_collection(cid, 0);
324 r = apply_transaction(store, &osr, std::move(t));
325 ASSERT_EQ(r, 0);
326 bool exists = store->exists(cid, hoid);
327 ASSERT_TRUE(!exists);
328 }
329 {
330 ObjectStore::Transaction t;
331 t.remove_collection(cid);
332 cerr << "remove collection" << std::endl;
333 r = apply_transaction(store, &osr, std::move(t));
334 ASSERT_EQ(r, 0);
335 }
336}
337
338TEST_P(StoreTest, IORemount) {
339 ObjectStore::Sequencer osr("test");
340 coll_t cid;
341 bufferlist bl;
342 bl.append("1234512345");
343 int r;
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 = apply_transaction(store, &osr, 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 = apply_transaction(store, &osr, std::move(t));
363 ASSERT_EQ(r, 0);
364 }
365 }
366 r = store->umount();
367 ASSERT_EQ(0, r);
368 r = store->mount();
369 ASSERT_EQ(0, r);
370 {
371 ObjectStore::Transaction t;
372 for (int n=1; n<=100; ++n) {
373 ghobject_t hoid(hobject_t(sobject_t("Object " + stringify(n), CEPH_NOSNAP)));
374 t.remove(cid, hoid);
375 }
376 t.remove_collection(cid);
377 r = apply_transaction(store, &osr, std::move(t));
378 ASSERT_EQ(r, 0);
379 }
380}
381
382TEST_P(StoreTest, UnprintableCharsName) {
383 ObjectStore::Sequencer osr("test");
384 coll_t cid;
385 string name = "funnychars_";
386 for (unsigned i = 0; i < 256; ++i) {
387 name.push_back(i);
388 }
389 ghobject_t oid(hobject_t(sobject_t(name, CEPH_NOSNAP)));
390 int r;
391 {
392 cerr << "create collection + object" << std::endl;
393 ObjectStore::Transaction t;
394 t.create_collection(cid, 0);
395 t.touch(cid, oid);
396 r = apply_transaction(store, &osr, std::move(t));
397 ASSERT_EQ(r, 0);
398 }
399 r = store->umount();
400 ASSERT_EQ(0, r);
401 r = store->mount();
402 ASSERT_EQ(0, r);
403 {
404 cout << "removing" << std::endl;
405 ObjectStore::Transaction t;
406 t.remove(cid, oid);
407 t.remove_collection(cid);
408 r = apply_transaction(store, &osr, std::move(t));
409 ASSERT_EQ(r, 0);
410 }
411}
412
413TEST_P(StoreTest, FiemapEmpty) {
414 ObjectStore::Sequencer osr("test");
415 coll_t cid;
416 int r = 0;
417 ghobject_t oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP)));
418 {
419 ObjectStore::Transaction t;
420 t.create_collection(cid, 0);
421 t.touch(cid, oid);
422 t.truncate(cid, oid, 100000);
423 r = apply_transaction(store, &osr, std::move(t));
424 ASSERT_EQ(r, 0);
425 }
426 {
427 bufferlist bl;
428 store->fiemap(cid, oid, 0, 100000, bl);
429 map<uint64_t,uint64_t> m, e;
430 bufferlist::iterator p = bl.begin();
431 ::decode(m, p);
432 cout << " got " << m << std::endl;
433 e[0] = 100000;
434 EXPECT_TRUE(m == e || m.empty());
435 }
436 {
437 ObjectStore::Transaction t;
438 t.remove(cid, oid);
439 t.remove_collection(cid);
440 cerr << "remove collection" << std::endl;
441 r = apply_transaction(store, &osr, std::move(t));
442 ASSERT_EQ(r, 0);
443 }
444}
445
446TEST_P(StoreTest, FiemapHoles) {
447 ObjectStore::Sequencer osr("test");
448 const uint64_t MAX_EXTENTS = 4000;
449 const uint64_t SKIP_STEP = 65536;
450 coll_t cid;
451 int r = 0;
452 ghobject_t oid(hobject_t(sobject_t("fiemap_object", CEPH_NOSNAP)));
453 bufferlist bl;
454 bl.append("foo");
455 {
456 ObjectStore::Transaction t;
457 t.create_collection(cid, 0);
458 t.touch(cid, oid);
459 for (uint64_t i = 0; i < MAX_EXTENTS; i++)
460 t.write(cid, oid, SKIP_STEP * i, 3, bl);
461 r = apply_transaction(store, &osr, std::move(t));
462 ASSERT_EQ(r, 0);
463 }
464 {
465 //fiemap test from 0 to SKIP_STEP * (MAX_EXTENTS - 1) + 3
466 bufferlist bl;
467 store->fiemap(cid, oid, 0, SKIP_STEP * (MAX_EXTENTS - 1) + 3, bl);
468 map<uint64_t,uint64_t> m, e;
469 bufferlist::iterator p = bl.begin();
470 ::decode(m, p);
471 cout << " got " << m << std::endl;
472 ASSERT_TRUE(!m.empty());
473 ASSERT_GE(m[0], 3u);
474 bool extents_exist = true;
475 if (m.size() == MAX_EXTENTS) {
476 for (uint64_t i = 0; i < MAX_EXTENTS; i++)
477 extents_exist = extents_exist && m.count(SKIP_STEP*i);
478 }
479 ASSERT_TRUE((m.size() == 1 &&
480 m[0] > SKIP_STEP * (MAX_EXTENTS - 1)) ||
481 (m.size() == MAX_EXTENTS && extents_exist));
482
483 // fiemap test from SKIP_STEP to SKIP_STEP * (MAX_EXTENTS - 2) + 3
484 // reset bufferlist and map
485 bl.clear();
486 m.clear();
487 e.clear();
488 store->fiemap(cid, oid, SKIP_STEP, SKIP_STEP * (MAX_EXTENTS - 2) + 3, bl);
489 p = bl.begin();
490 ::decode(m, p);
491 cout << " got " << m << std::endl;
492 ASSERT_TRUE(!m.empty());
493 ASSERT_GE(m[SKIP_STEP], 3u);
494 extents_exist = true;
495 if (m.size() == (MAX_EXTENTS - 2)) {
496 for (uint64_t i = 1; i < MAX_EXTENTS - 1; i++)
497 extents_exist = extents_exist && m.count(SKIP_STEP*i);
498 }
499 ASSERT_TRUE((m.size() == 1 &&
500 m[SKIP_STEP] > SKIP_STEP * (MAX_EXTENTS - 2)) ||
501 (m.size() == (MAX_EXTENTS - 1) && extents_exist));
502 }
503 {
504 ObjectStore::Transaction t;
505 t.remove(cid, oid);
506 t.remove_collection(cid);
507 cerr << "remove collection" << std::endl;
508 r = apply_transaction(store, &osr, std::move(t));
509 ASSERT_EQ(r, 0);
510 }
511}
512
513TEST_P(StoreTest, SimpleMetaColTest) {
514 ObjectStore::Sequencer osr("test");
515 coll_t cid;
516 int r = 0;
517 {
518 ObjectStore::Transaction t;
519 t.create_collection(cid, 0);
520 cerr << "create collection" << std::endl;
521 r = apply_transaction(store, &osr, std::move(t));
522 ASSERT_EQ(r, 0);
523 }
524 {
525 ObjectStore::Transaction t;
526 t.remove_collection(cid);
527 cerr << "remove collection" << std::endl;
528 r = apply_transaction(store, &osr, std::move(t));
529 ASSERT_EQ(r, 0);
530 }
531 {
532 ObjectStore::Transaction t;
533 t.create_collection(cid, 0);
534 cerr << "add collection" << std::endl;
535 r = apply_transaction(store, &osr, std::move(t));
536 ASSERT_EQ(r, 0);
537 }
538 {
539 ObjectStore::Transaction t;
540 t.remove_collection(cid);
541 cerr << "remove collection" << std::endl;
542 r = apply_transaction(store, &osr, std::move(t));
543 ASSERT_EQ(r, 0);
544 }
545}
546
547TEST_P(StoreTest, SimplePGColTest) {
548 ObjectStore::Sequencer osr("test");
549 coll_t cid(spg_t(pg_t(1,2), shard_id_t::NO_SHARD));
550 int r = 0;
551 {
552 ObjectStore::Transaction t;
553 t.create_collection(cid, 4);
554 cerr << "create collection" << std::endl;
555 r = apply_transaction(store, &osr, std::move(t));
556 ASSERT_EQ(r, 0);
557 }
558 {
559 ObjectStore::Transaction t;
560 t.remove_collection(cid);
561 cerr << "remove collection" << std::endl;
562 r = apply_transaction(store, &osr, std::move(t));
563 ASSERT_EQ(r, 0);
564 }
565 {
566 ObjectStore::Transaction t;
567 t.create_collection(cid, 4);
568 cerr << "add collection" << std::endl;
569 r = apply_transaction(store, &osr, std::move(t));
570 ASSERT_EQ(r, 0);
571 }
572 {
573 ObjectStore::Transaction t;
574 t.remove_collection(cid);
575 cerr << "remove collection" << std::endl;
576 r = apply_transaction(store, &osr, std::move(t));
577 ASSERT_EQ(r, 0);
578 }
579}
580
581TEST_P(StoreTest, SimpleColPreHashTest) {
582 ObjectStore::Sequencer osr("test");
583 // Firstly we will need to revert the value making sure
584 // collection hint actually works
585 int merge_threshold = g_ceph_context->_conf->filestore_merge_threshold;
586 std::ostringstream oss;
587 if (merge_threshold > 0) {
588 oss << "-" << merge_threshold;
589 g_ceph_context->_conf->set_val("filestore_merge_threshold", oss.str().c_str());
590 }
591
592 uint32_t pg_num = 128;
593
594 boost::uniform_int<> pg_id_range(0, pg_num);
595 gen_type rng(time(NULL));
596 int pg_id = pg_id_range(rng);
597
598 int objs_per_folder = abs(merge_threshold) * 16 * g_ceph_context->_conf->filestore_split_multiple;
599 boost::uniform_int<> folders_range(5, 256);
600 uint64_t expected_num_objs = (uint64_t)objs_per_folder * (uint64_t)folders_range(rng);
601
602 coll_t cid(spg_t(pg_t(pg_id, 15), shard_id_t::NO_SHARD));
603 int r;
604 {
605 // Create a collection along with a hint
606 ObjectStore::Transaction t;
607 t.create_collection(cid, 5);
608 cerr << "create collection" << std::endl;
609 bufferlist hint;
610 ::encode(pg_num, hint);
611 ::encode(expected_num_objs, hint);
612 t.collection_hint(cid, ObjectStore::Transaction::COLL_HINT_EXPECTED_NUM_OBJECTS, hint);
613 cerr << "collection hint" << std::endl;
614 r = apply_transaction(store, &osr, std::move(t));
615 ASSERT_EQ(r, 0);
616 }
617 {
618 // Remove the collection
619 ObjectStore::Transaction t;
620 t.remove_collection(cid);
621 cerr << "remove collection" << std::endl;
622 r = apply_transaction(store, &osr, std::move(t));
623 ASSERT_EQ(r, 0);
624 }
625 // Revert the config change so that it does not affect the split/merge tests
626 if (merge_threshold > 0) {
627 oss.str("");
628 oss << merge_threshold;
629 g_ceph_context->_conf->set_val("filestore_merge_threshold", oss.str().c_str());
630 }
631}
632
633TEST_P(StoreTest, SmallBlockWrites) {
634 ObjectStore::Sequencer osr("test");
635 int r;
636 coll_t cid;
637 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
638 {
639 ObjectStore::Transaction t;
640 t.create_collection(cid, 0);
641 cerr << "Creating collection " << cid << std::endl;
642 r = apply_transaction(store, &osr, std::move(t));
643 ASSERT_EQ(r, 0);
644 }
645 bufferlist a;
646 bufferptr ap(0x1000);
647 memset(ap.c_str(), 'a', 0x1000);
648 a.append(ap);
649 bufferlist b;
650 bufferptr bp(0x1000);
651 memset(bp.c_str(), 'b', 0x1000);
652 b.append(bp);
653 bufferlist c;
654 bufferptr cp(0x1000);
655 memset(cp.c_str(), 'c', 0x1000);
656 c.append(cp);
657 bufferptr zp(0x1000);
658 zp.zero();
659 bufferlist z;
660 z.append(zp);
661 {
662 ObjectStore::Transaction t;
663 t.write(cid, hoid, 0, 0x1000, a);
664 r = apply_transaction(store, &osr, std::move(t));
665 ASSERT_EQ(r, 0);
666
667 bufferlist in, exp;
668 r = store->read(cid, hoid, 0, 0x4000, in);
669 ASSERT_EQ(0x1000, r);
670 exp.append(a);
671 ASSERT_TRUE(bl_eq(exp, in));
672 }
673 {
674 ObjectStore::Transaction t;
675 t.write(cid, hoid, 0x1000, 0x1000, b);
676 r = apply_transaction(store, &osr, std::move(t));
677 ASSERT_EQ(r, 0);
678
679 bufferlist in, exp;
680 r = store->read(cid, hoid, 0, 0x4000, in);
681 ASSERT_EQ(0x2000, r);
682 exp.append(a);
683 exp.append(b);
684 ASSERT_TRUE(bl_eq(exp, in));
685 }
686 {
687 ObjectStore::Transaction t;
688 t.write(cid, hoid, 0x3000, 0x1000, c);
689 r = apply_transaction(store, &osr, std::move(t));
690 ASSERT_EQ(r, 0);
691
692 bufferlist in, exp;
693 r = store->read(cid, hoid, 0, 0x4000, in);
694 ASSERT_EQ(0x4000, r);
695 exp.append(a);
696 exp.append(b);
697 exp.append(z);
698 exp.append(c);
699 ASSERT_TRUE(bl_eq(exp, in));
700 }
701 {
702 ObjectStore::Transaction t;
703 t.write(cid, hoid, 0x2000, 0x1000, a);
704 r = apply_transaction(store, &osr, std::move(t));
705 ASSERT_EQ(r, 0);
706
707 bufferlist in, exp;
708 r = store->read(cid, hoid, 0, 0x4000, in);
709 ASSERT_EQ(0x4000, r);
710 exp.append(a);
711 exp.append(b);
712 exp.append(a);
713 exp.append(c);
714 ASSERT_TRUE(bl_eq(exp, in));
715 }
716 {
717 ObjectStore::Transaction t;
718 t.write(cid, hoid, 0, 0x1000, c);
719 r = apply_transaction(store, &osr, std::move(t));
720 ASSERT_EQ(r, 0);
721 }
722 {
723 bufferlist in, exp;
724 r = store->read(cid, hoid, 0, 0x4000, in);
725 ASSERT_EQ(0x4000, r);
726 exp.append(c);
727 exp.append(b);
728 exp.append(a);
729 exp.append(c);
730 ASSERT_TRUE(bl_eq(exp, in));
731 }
732 {
733 ObjectStore::Transaction t;
734 t.remove(cid, hoid);
735 t.remove_collection(cid);
736 cerr << "Cleaning" << std::endl;
737 r = apply_transaction(store, &osr, std::move(t));
738 ASSERT_EQ(r, 0);
739 }
740}
741
742TEST_P(StoreTest, BufferCacheReadTest) {
743 ObjectStore::Sequencer osr("test");
744 int r;
745 coll_t cid;
746 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
747 {
748 bufferlist in;
749 r = store->read(cid, hoid, 0, 5, in);
750 ASSERT_EQ(-ENOENT, r);
751 }
752 {
753 ObjectStore::Transaction t;
754 t.create_collection(cid, 0);
755 cerr << "Creating collection " << cid << std::endl;
756 r = apply_transaction(store, &osr, std::move(t));
757 ASSERT_EQ(r, 0);
758 }
759 {
760 bool exists = store->exists(cid, hoid);
761 ASSERT_TRUE(!exists);
762
763 ObjectStore::Transaction t;
764 t.touch(cid, hoid);
765 cerr << "Creating object " << hoid << std::endl;
766 r = apply_transaction(store, &osr, std::move(t));
767 ASSERT_EQ(r, 0);
768
769 exists = store->exists(cid, hoid);
770 ASSERT_EQ(true, exists);
771 }
772 {
773 ObjectStore::Transaction t;
774 bufferlist bl, newdata;
775 bl.append("abcde");
776 t.write(cid, hoid, 0, 5, bl);
777 t.write(cid, hoid, 10, 5, bl);
778 cerr << "TwinWrite" << std::endl;
779 r = apply_transaction(store, &osr, std::move(t));
780 ASSERT_EQ(r, 0);
781
782 r = store->read(cid, hoid, 0, 15, newdata);
783 ASSERT_EQ(r, 15);
784 {
785 bufferlist expected;
786 expected.append(bl);
787 expected.append_zero(5);
788 expected.append(bl);
789 ASSERT_TRUE(bl_eq(expected, newdata));
790 }
791 }
792 //overwrite over the same extents
793 {
794 ObjectStore::Transaction t;
795 bufferlist bl, newdata;
796 bl.append("edcba");
797 t.write(cid, hoid, 0, 5, bl);
798 t.write(cid, hoid, 10, 5, bl);
799 cerr << "TwinWrite" << std::endl;
800 r = apply_transaction(store, &osr, std::move(t));
801 ASSERT_EQ(r, 0);
802
803 r = store->read(cid, hoid, 0, 15, newdata);
804 ASSERT_EQ(r, 15);
805 {
806 bufferlist expected;
807 expected.append(bl);
808 expected.append_zero(5);
809 expected.append(bl);
810 ASSERT_TRUE(bl_eq(expected, newdata));
811 }
812 }
813 //additional write to an unused region of some blob
814 {
815 ObjectStore::Transaction t;
816 bufferlist bl2, newdata;
817 bl2.append("1234567890");
818
819 t.write(cid, hoid, 20, bl2.length(), bl2);
820 cerr << "Append" << std::endl;
821 r = apply_transaction(store, &osr, std::move(t));
822 ASSERT_EQ(r, 0);
823
824 r = store->read(cid, hoid, 0, 30, newdata);
825 ASSERT_EQ(r, 30);
826 {
827 bufferlist expected;
828 expected.append("edcba");
829 expected.append_zero(5);
830 expected.append("edcba");
831 expected.append_zero(5);
832 expected.append(bl2);
833
834 ASSERT_TRUE(bl_eq(expected, newdata));
835 }
836 }
837 //additional write to an unused region of some blob and partial owerite over existing extents
838 {
839 ObjectStore::Transaction t;
840 bufferlist bl, bl2, bl3, newdata;
841 bl.append("DCB");
842 bl2.append("1234567890");
843 bl3.append("BA");
844
845 t.write(cid, hoid, 30, bl2.length(), bl2);
846 t.write(cid, hoid, 1, bl.length(), bl);
847 t.write(cid, hoid, 13, bl3.length(), bl3);
848 cerr << "TripleWrite" << std::endl;
849 r = apply_transaction(store, &osr, std::move(t));
850 ASSERT_EQ(r, 0);
851
852 r = store->read(cid, hoid, 0, 40, newdata);
853 ASSERT_EQ(r, 40);
854 {
855 bufferlist expected;
856 expected.append("eDCBa");
857 expected.append_zero(5);
858 expected.append("edcBA");
859 expected.append_zero(5);
860 expected.append(bl2);
861 expected.append(bl2);
862
863 ASSERT_TRUE(bl_eq(expected, newdata));
864 }
865 }
866}
867
868void doCompressionTest( boost::scoped_ptr<ObjectStore>& store)
869{
870 ObjectStore::Sequencer osr("test");
871 int r;
872 coll_t cid;
873 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
874 {
875 bufferlist in;
876 r = store->read(cid, hoid, 0, 5, in);
877 ASSERT_EQ(-ENOENT, r);
878 }
879 {
880 ObjectStore::Transaction t;
881 t.create_collection(cid, 0);
882 cerr << "Creating collection " << cid << std::endl;
883 r = apply_transaction(store, &osr, std::move(t));
884 ASSERT_EQ(r, 0);
885 }
886 {
887 bool exists = store->exists(cid, hoid);
888 ASSERT_TRUE(!exists);
889
890 ObjectStore::Transaction t;
891 t.touch(cid, hoid);
892 cerr << "Creating object " << hoid << std::endl;
893 r = apply_transaction(store, &osr, std::move(t));
894 ASSERT_EQ(r, 0);
895
896 exists = store->exists(cid, hoid);
897 ASSERT_EQ(true, exists);
898 }
899 std::string data;
900 data.resize(0x10000 * 4);
901 for(size_t i = 0;i < data.size(); i++)
902 data[i] = i / 256;
903 {
904 ObjectStore::Transaction t;
905 bufferlist bl, newdata;
906 bl.append(data);
907 t.write(cid, hoid, 0, bl.length(), bl);
908 cerr << "CompressibleData (4xAU) Write" << std::endl;
909 r = apply_transaction(store, &osr, std::move(t));
910 ASSERT_EQ(r, 0);
911
912 r = store->read(cid, hoid, 0, data.size() , newdata);
913
914 ASSERT_EQ(r, (int)data.size());
915 {
916 bufferlist expected;
917 expected.append(data);
918 ASSERT_TRUE(bl_eq(expected, newdata));
919 }
920 newdata.clear();
921 r = store->read(cid, hoid, 0, 711 , newdata);
922 ASSERT_EQ(r, 711);
923 {
924 bufferlist expected;
925 expected.append(data.substr(0,711));
926 ASSERT_TRUE(bl_eq(expected, newdata));
927 }
928 newdata.clear();
929 r = store->read(cid, hoid, 0xf00f, data.size(), newdata);
930 ASSERT_EQ(r, int(data.size() - 0xf00f) );
931 {
932 bufferlist expected;
933 expected.append(data.substr(0xf00f));
934 ASSERT_TRUE(bl_eq(expected, newdata));
935 }
936 {
937 struct store_statfs_t statfs;
938 int r = store->statfs(&statfs);
939 ASSERT_EQ(r, 0);
940 ASSERT_EQ(statfs.stored, (unsigned)data.size());
941 ASSERT_LE(statfs.compressed, (unsigned)data.size());
942 ASSERT_EQ(statfs.compressed_original, (unsigned)data.size());
943 ASSERT_LE(statfs.compressed_allocated, (unsigned)data.size());
944 }
945 }
946 std::string data2;
947 data2.resize(0x10000 * 4 - 0x9000);
948 for(size_t i = 0;i < data2.size(); i++)
949 data2[i] = (i+1) / 256;
950 {
951 ObjectStore::Transaction t;
952 bufferlist bl, newdata;
953 bl.append(data2);
954 t.write(cid, hoid, 0x8000, bl.length(), bl);
955 cerr << "CompressibleData partial overwrite" << std::endl;
956 r = apply_transaction(store, &osr, std::move(t));
957 ASSERT_EQ(r, 0);
958
959 r = store->read(cid, hoid, 0, 0x10000, newdata);
960 ASSERT_EQ(r, (int)0x10000);
961 {
962 bufferlist expected;
963 expected.append(data.substr(0, 0x8000));
964 expected.append(data2.substr(0, 0x8000));
965 ASSERT_TRUE(bl_eq(expected, newdata));
966 }
967 newdata.clear();
968 r = store->read(cid, hoid, 0x9000, 711 , newdata);
969 ASSERT_EQ(r, 711);
970 {
971 bufferlist expected;
972 expected.append(data2.substr(0x1000,711));
973 ASSERT_TRUE(bl_eq(expected, newdata));
974 }
975 newdata.clear();
976 r = store->read(cid, hoid, 0x0, 0x40000, newdata);
977 ASSERT_EQ(r, int(0x40000) );
978 {
979 bufferlist expected;
980 expected.append(data.substr(0, 0x8000));
981 expected.append(data2.substr(0, 0x37000));
982 expected.append(data.substr(0x3f000, 0x1000));
983 ASSERT_TRUE(bl_eq(expected, newdata));
984 }
985 }
986 data2.resize(0x3f000);
987 for(size_t i = 0;i < data2.size(); i++)
988 data2[i] = (i+2) / 256;
989 {
990 ObjectStore::Transaction t;
991 bufferlist bl, newdata;
992 bl.append(data2);
993 t.write(cid, hoid, 0, bl.length(), bl);
994 cerr << "CompressibleData partial overwrite, two extents overlapped, single one to be removed" << std::endl;
995 r = apply_transaction(store, &osr, std::move(t));
996 ASSERT_EQ(r, 0);
997
998 r = store->read(cid, hoid, 0, 0x3e000 - 1, newdata);
999 ASSERT_EQ(r, (int)0x3e000 - 1);
1000 {
1001 bufferlist expected;
1002 expected.append(data2.substr(0, 0x3e000 - 1));
1003 ASSERT_TRUE(bl_eq(expected, newdata));
1004 }
1005 newdata.clear();
1006 r = store->read(cid, hoid, 0x3e000-1, 0x2001, newdata);
1007 ASSERT_EQ(r, 0x2001);
1008 {
1009 bufferlist expected;
1010 expected.append(data2.substr(0x3e000-1, 0x1001));
1011 expected.append(data.substr(0x3f000, 0x1000));
1012 ASSERT_TRUE(bl_eq(expected, newdata));
1013 }
1014 newdata.clear();
1015 r = store->read(cid, hoid, 0x0, 0x40000, newdata);
1016 ASSERT_EQ(r, int(0x40000) );
1017 {
1018 bufferlist expected;
1019 expected.append(data2.substr(0, 0x3f000));
1020 expected.append(data.substr(0x3f000, 0x1000));
1021 ASSERT_TRUE(bl_eq(expected, newdata));
1022 }
1023 }
1024 data.resize(0x1001);
1025 for(size_t i = 0;i < data.size(); i++)
1026 data[i] = (i+3) / 256;
1027 {
1028 ObjectStore::Transaction t;
1029 bufferlist bl, newdata;
1030 bl.append(data);
1031 t.write(cid, hoid, 0x3f000-1, bl.length(), bl);
1032 cerr << "Small chunk partial overwrite, two extents overlapped, single one to be removed" << std::endl;
1033 r = apply_transaction(store, &osr, std::move(t));
1034 ASSERT_EQ(r, 0);
1035
1036 r = store->read(cid, hoid, 0x3e000, 0x2000, newdata);
1037 ASSERT_EQ(r, (int)0x2000);
1038 {
1039 bufferlist expected;
1040 expected.append(data2.substr(0x3e000, 0x1000 - 1));
1041 expected.append(data.substr(0, 0x1001));
1042 ASSERT_TRUE(bl_eq(expected, newdata));
1043 }
1044 }
1045 {
1046 ObjectStore::Transaction t;
1047 t.remove(cid, hoid);
1048 cerr << "Cleaning object" << std::endl;
1049 r = apply_transaction(store, &osr, std::move(t));
1050 ASSERT_EQ(r, 0);
1051 }
1052 //force fsck
1053 EXPECT_EQ(store->umount(), 0);
1054 EXPECT_EQ(store->mount(), 0);
1055 auto orig_min_blob_size = g_conf->bluestore_compression_min_blob_size;
1056 {
1057 g_conf->set_val("bluestore_compression_min_blob_size", "262144");
1058 g_ceph_context->_conf->apply_changes(NULL);
1059 data.resize(0x10000*6);
1060
1061 for(size_t i = 0;i < data.size(); i++)
1062 data[i] = i / 256;
1063 ObjectStore::Transaction t;
1064 bufferlist bl, newdata;
1065 bl.append(data);
1066 t.write(cid, hoid, 0, bl.length(), bl);
1067 cerr << "CompressibleData large blob" << std::endl;
1068 r = apply_transaction(store, &osr, std::move(t));
1069 ASSERT_EQ(r, 0);
1070 }
1071 //force fsck
1072 EXPECT_EQ(store->umount(), 0);
1073 EXPECT_EQ(store->mount(), 0);
1074
1075 {
1076 ObjectStore::Transaction t;
1077 t.remove(cid, hoid);
1078 t.remove_collection(cid);
1079 cerr << "Cleaning" << std::endl;
1080 r = apply_transaction(store, &osr, std::move(t));
1081 ASSERT_EQ(r, 0);
1082 }
1083 g_conf->set_val("bluestore_compression_min_blob_size", stringify(orig_min_blob_size));
1084 g_ceph_context->_conf->apply_changes(NULL);
1085}
1086
1087TEST_P(StoreTest, CompressionTest) {
1088 if (string(GetParam()) != "bluestore")
1089 return;
1090
1091 g_conf->set_val("bluestore_compression_algorithm", "snappy");
1092 g_conf->set_val("bluestore_compression_mode", "force");
1093
1094 g_ceph_context->_conf->apply_changes(NULL);
1095
1096 doCompressionTest(store);
1097
1098 g_conf->set_val("bluestore_compression_algorithm", "zlib");
1099 g_conf->set_val("bluestore_compression_mode", "force");
1100 g_ceph_context->_conf->apply_changes(NULL);
1101
1102 doCompressionTest(store);
1103
1104 g_conf->set_val("bluestore_compression_algorithm", "snappy");
1105 g_conf->set_val("bluestore_compression_mode", "none");
1106 g_ceph_context->_conf->apply_changes(NULL);
1107}
1108
1109TEST_P(StoreTest, SimpleObjectTest) {
1110 ObjectStore::Sequencer osr("test");
1111 int r;
1112 coll_t cid;
1113 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1114 {
1115 bufferlist in;
1116 r = store->read(cid, hoid, 0, 5, in);
1117 ASSERT_EQ(-ENOENT, r);
1118 }
1119 {
1120 ObjectStore::Transaction t;
1121 t.create_collection(cid, 0);
1122 cerr << "Creating collection " << cid << std::endl;
1123 r = apply_transaction(store, &osr, std::move(t));
1124 ASSERT_EQ(r, 0);
1125 }
1126 {
1127 bool exists = store->exists(cid, hoid);
1128 ASSERT_TRUE(!exists);
1129
1130 ObjectStore::Transaction t;
1131 t.touch(cid, hoid);
1132 cerr << "Creating object " << hoid << std::endl;
1133 r = apply_transaction(store, &osr, std::move(t));
1134 ASSERT_EQ(r, 0);
1135
1136 exists = store->exists(cid, hoid);
1137 ASSERT_EQ(true, exists);
1138 }
1139 {
1140 ObjectStore::Transaction t;
1141 t.remove(cid, hoid);
1142 t.touch(cid, hoid);
1143 cerr << "Remove then create" << std::endl;
1144 r = apply_transaction(store, &osr, std::move(t));
1145 ASSERT_EQ(r, 0);
1146 }
1147 {
1148 ObjectStore::Transaction t;
1149 bufferlist bl, orig;
1150 bl.append("abcde");
1151 orig = bl;
1152 t.remove(cid, hoid);
1153 t.write(cid, hoid, 0, 5, bl);
1154 cerr << "Remove then create" << std::endl;
1155 r = apply_transaction(store, &osr, std::move(t));
1156 ASSERT_EQ(r, 0);
1157
1158 bufferlist in;
1159 r = store->read(cid, hoid, 0, 5, in);
1160 ASSERT_EQ(5, r);
1161 ASSERT_TRUE(bl_eq(orig, in));
1162 }
1163 {
1164 ObjectStore::Transaction t;
1165 bufferlist bl, exp;
1166 bl.append("abcde");
1167 exp = bl;
1168 exp.append(bl);
1169 t.write(cid, hoid, 5, 5, bl);
1170 cerr << "Append" << std::endl;
1171 r = apply_transaction(store, &osr, std::move(t));
1172 ASSERT_EQ(r, 0);
1173
1174 bufferlist in;
1175 r = store->read(cid, hoid, 0, 10, in);
1176 ASSERT_EQ(10, r);
1177 ASSERT_TRUE(bl_eq(exp, in));
1178 }
1179 {
1180 ObjectStore::Transaction t;
1181 bufferlist bl, exp;
1182 bl.append("abcdeabcde");
1183 exp = bl;
1184 t.write(cid, hoid, 0, 10, bl);
1185 cerr << "Full overwrite" << std::endl;
1186 r = apply_transaction(store, &osr, std::move(t));
1187 ASSERT_EQ(r, 0);
1188
1189 bufferlist in;
1190 r = store->read(cid, hoid, 0, 10, in);
1191 ASSERT_EQ(10, r);
1192 ASSERT_TRUE(bl_eq(exp, in));
1193 }
1194 {
1195 ObjectStore::Transaction t;
1196 bufferlist bl;
1197 bl.append("abcde");
1198 t.write(cid, hoid, 3, 5, bl);
1199 cerr << "Partial overwrite" << std::endl;
1200 r = apply_transaction(store, &osr, std::move(t));
1201 ASSERT_EQ(r, 0);
1202
1203 bufferlist in, exp;
1204 exp.append("abcabcdede");
1205 r = store->read(cid, hoid, 0, 10, in);
1206 ASSERT_EQ(10, r);
1207 in.hexdump(cout);
1208 ASSERT_TRUE(bl_eq(exp, in));
1209 }
1210 {
1211 {
1212 ObjectStore::Transaction t;
1213 bufferlist bl;
1214 bl.append("fghij");
1215 t.truncate(cid, hoid, 0);
1216 t.write(cid, hoid, 5, 5, bl);
1217 cerr << "Truncate + hole" << std::endl;
1218 r = apply_transaction(store, &osr, std::move(t));
1219 ASSERT_EQ(r, 0);
1220 }
1221 {
1222 ObjectStore::Transaction t;
1223 bufferlist bl;
1224 bl.append("abcde");
1225 t.write(cid, hoid, 0, 5, bl);
1226 cerr << "Reverse fill-in" << std::endl;
1227 r = apply_transaction(store, &osr, std::move(t));
1228 ASSERT_EQ(r, 0);
1229 }
1230
1231 bufferlist in, exp;
1232 exp.append("abcdefghij");
1233 r = store->read(cid, hoid, 0, 10, in);
1234 ASSERT_EQ(10, r);
1235 in.hexdump(cout);
1236 ASSERT_TRUE(bl_eq(exp, in));
1237 }
1238 {
1239 ObjectStore::Transaction t;
1240 bufferlist bl;
1241 bl.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1242 t.write(cid, hoid, 0, bl.length(), bl);
1243 cerr << "larger overwrite" << std::endl;
1244 r = apply_transaction(store, &osr, std::move(t));
1245 ASSERT_EQ(r, 0);
1246
1247 bufferlist in;
1248 r = store->read(cid, hoid, 0, bl.length(), in);
1249 ASSERT_EQ((int)bl.length(), r);
1250 in.hexdump(cout);
1251 ASSERT_TRUE(bl_eq(bl, in));
1252 }
1253 {
1254 bufferlist bl;
1255 bl.append("abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234abcde01234012340123401234");
1256
1257 //test: offset=len=0 mean read all data
1258 bufferlist in;
1259 r = store->read(cid, hoid, 0, 0, in);
1260 ASSERT_EQ((int)bl.length(), r);
1261 in.hexdump(cout);
1262 ASSERT_TRUE(bl_eq(bl, in));
1263 }
1264 {
1265 //verifying unaligned csums
1266 std::string s1("1"), s2(0x1000, '2'), s3("00");
1267 {
1268 ObjectStore::Transaction t;
1269 bufferlist bl;
1270 bl.append(s1);
1271 bl.append(s2);
1272 t.truncate(cid, hoid, 0);
1273 t.write(cid, hoid, 0x1000-1, bl.length(), bl);
1274 cerr << "Write unaligned csum, stage 1" << std::endl;
1275 r = apply_transaction(store, &osr, std::move(t));
1276 ASSERT_EQ(r, 0);
1277 }
1278
1279 bufferlist in, exp1, exp2, exp3;
1280 exp1.append(s1);
1281 exp2.append(s2);
1282 exp3.append(s3);
1283 r = store->read(cid, hoid, 0x1000-1, 1, in);
1284 ASSERT_EQ(1, r);
1285 ASSERT_TRUE(bl_eq(exp1, in));
1286 in.clear();
1287 r = store->read(cid, hoid, 0x1000, 0x1000, in);
1288 ASSERT_EQ(0x1000, r);
1289 ASSERT_TRUE(bl_eq(exp2, in));
1290
1291 {
1292 ObjectStore::Transaction t;
1293 bufferlist bl;
1294 bl.append(s3);
1295 t.write(cid, hoid, 1, bl.length(), bl);
1296 cerr << "Write unaligned csum, stage 2" << std::endl;
1297 r = apply_transaction(store, &osr, std::move(t));
1298 ASSERT_EQ(r, 0);
1299 }
1300 in.clear();
1301 r = store->read(cid, hoid, 1, 2, in);
1302 ASSERT_EQ(2, r);
1303 ASSERT_TRUE(bl_eq(exp3, in));
1304 in.clear();
1305 r = store->read(cid, hoid, 0x1000-1, 1, in);
1306 ASSERT_EQ(1, r);
1307 ASSERT_TRUE(bl_eq(exp1, in));
1308 in.clear();
1309 r = store->read(cid, hoid, 0x1000, 0x1000, in);
1310 ASSERT_EQ(0x1000, r);
1311 ASSERT_TRUE(bl_eq(exp2, in));
1312
1313 }
1314
1315 {
1316 ObjectStore::Transaction t;
1317 t.remove(cid, hoid);
1318 t.remove_collection(cid);
1319 cerr << "Cleaning" << std::endl;
1320 r = apply_transaction(store, &osr, std::move(t));
1321 ASSERT_EQ(r, 0);
1322 }
1323}
1324
1325#if defined(HAVE_LIBAIO)
1326TEST_P(StoreTestSpecificAUSize, BluestoreStatFSTest) {
1327 if(string(GetParam()) != "bluestore")
1328 return;
1329 StartDeferred(65536);
1330 g_conf->set_val("bluestore_compression_mode", "force");
1331
1332 // just a big number to disble gc
1333 g_conf->set_val("bluestore_gc_enable_total_threshold", "100000");
1334 g_conf->apply_changes(NULL);
1335 int r;
1336
1337 ObjectStore::Sequencer osr("test");
1338 coll_t cid;
1339 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1340 ghobject_t hoid2 = hoid;
1341 hoid2.hobj.snap = 1;
1342 {
1343 bufferlist in;
1344 r = store->read(cid, hoid, 0, 5, in);
1345 ASSERT_EQ(-ENOENT, r);
1346 }
1347 {
1348 ObjectStore::Transaction t;
1349 t.create_collection(cid, 0);
1350 cerr << "Creating collection " << cid << std::endl;
1351 r = apply_transaction(store, &osr, std::move(t));
1352 ASSERT_EQ(r, 0);
1353 }
1354 {
1355 bool exists = store->exists(cid, hoid);
1356 ASSERT_TRUE(!exists);
1357
1358 ObjectStore::Transaction t;
1359 t.touch(cid, hoid);
1360 cerr << "Creating object " << hoid << std::endl;
1361 r = apply_transaction(store, &osr, std::move(t));
1362 ASSERT_EQ(r, 0);
1363
1364 exists = store->exists(cid, hoid);
1365 ASSERT_EQ(true, exists);
1366 }
1367 {
1368 struct store_statfs_t statfs;
1369 int r = store->statfs(&statfs);
1370 ASSERT_EQ(r, 0);
1371 ASSERT_EQ( 0u, statfs.allocated);
1372 ASSERT_EQ( 0u, statfs.stored);
1373 ASSERT_EQ(g_conf->bluestore_block_size, statfs.total);
1374 ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf->bluestore_block_size);
1375 //force fsck
1376 EXPECT_EQ(store->umount(), 0);
1377 EXPECT_EQ(store->mount(), 0);
1378 }
1379 {
1380 ObjectStore::Transaction t;
1381 bufferlist bl;
1382 bl.append("abcde");
1383 t.write(cid, hoid, 0, 5, bl);
1384 cerr << "Append 5 bytes" << std::endl;
1385 r = apply_transaction(store, &osr, std::move(t));
1386 ASSERT_EQ(r, 0);
1387
1388 struct store_statfs_t statfs;
1389 int r = store->statfs(&statfs);
1390 ASSERT_EQ(r, 0);
1391 ASSERT_EQ(5, statfs.stored);
1392 ASSERT_EQ(0x10000, statfs.allocated);
1393 ASSERT_EQ(0, statfs.compressed);
1394 ASSERT_EQ(0, statfs.compressed_original);
1395 ASSERT_EQ(0, statfs.compressed_allocated);
1396 //force fsck
1397 EXPECT_EQ(store->umount(), 0);
1398 EXPECT_EQ(store->mount(), 0);
1399 }
1400 {
1401 ObjectStore::Transaction t;
1402 std::string s(0x30000, 'a');
1403 bufferlist bl;
1404 bl.append(s);
1405 t.write(cid, hoid, 0x10000, bl.length(), bl);
1406 cerr << "Append 0x30000 compressible bytes" << std::endl;
1407 r = apply_transaction(store, &osr, std::move(t));
1408 ASSERT_EQ(r, 0);
1409
1410 struct store_statfs_t statfs;
1411 int r = store->statfs(&statfs);
1412 ASSERT_EQ(r, 0);
1413 ASSERT_EQ(0x30005, statfs.stored);
1414 ASSERT_EQ(0x30000, statfs.allocated);
1415 ASSERT_LE(statfs.compressed, 0x10000);
1416 ASSERT_EQ(0x20000, statfs.compressed_original);
1417 ASSERT_EQ(statfs.compressed_allocated, 0x10000);
1418 //force fsck
1419 EXPECT_EQ(store->umount(), 0);
1420 EXPECT_EQ(store->mount(), 0);
1421 }
1422 {
1423 ObjectStore::Transaction t;
1424 t.zero(cid, hoid, 1, 3);
1425 t.zero(cid, hoid, 0x20000, 9);
1426 cerr << "Punch hole at 1~3, 0x20000~9" << std::endl;
1427 r = apply_transaction(store, &osr, std::move(t));
1428 ASSERT_EQ(r, 0);
1429
1430 struct store_statfs_t statfs;
1431 int r = store->statfs(&statfs);
1432 ASSERT_EQ(r, 0);
1433 ASSERT_EQ(0x30005 - 3 - 9, statfs.stored);
1434 ASSERT_EQ(0x30000, statfs.allocated);
1435 ASSERT_LE(statfs.compressed, 0x10000);
1436 ASSERT_EQ(0x20000 - 9, statfs.compressed_original);
1437 ASSERT_EQ(statfs.compressed_allocated, 0x10000);
1438 //force fsck
1439 EXPECT_EQ(store->umount(), 0);
1440 EXPECT_EQ(store->mount(), 0);
1441 }
1442 {
1443 ObjectStore::Transaction t;
1444 std::string s(0x1000, 'b');
1445 bufferlist bl;
1446 bl.append(s);
1447 t.write(cid, hoid, 1, bl.length(), bl);
1448 t.write(cid, hoid, 0x10001, bl.length(), bl);
1449 cerr << "Overwrite first and second(compressible) extents" << std::endl;
1450 r = apply_transaction(store, &osr, std::move(t));
1451 ASSERT_EQ(r, 0);
1452
1453 struct store_statfs_t statfs;
1454 int r = store->statfs(&statfs);
1455 ASSERT_EQ(r, 0);
1456 ASSERT_EQ(0x30001 - 9 + 0x1000, statfs.stored);
1457 ASSERT_EQ(0x40000, statfs.allocated);
1458 ASSERT_LE(statfs.compressed, 0x10000);
1459 ASSERT_EQ(0x20000 - 9 - 0x1000, statfs.compressed_original);
1460 ASSERT_EQ(statfs.compressed_allocated, 0x10000);
1461 //force fsck
1462 EXPECT_EQ(store->umount(), 0);
1463 EXPECT_EQ(store->mount(), 0);
1464 }
1465 {
1466 ObjectStore::Transaction t;
1467 std::string s(0x10000, 'c');
1468 bufferlist bl;
1469 bl.append(s);
1470 t.write(cid, hoid, 0x10000, bl.length(), bl);
1471 t.write(cid, hoid, 0x20000, bl.length(), bl);
1472 t.write(cid, hoid, 0x30000, bl.length(), bl);
1473 cerr << "Overwrite compressed extent with 3 uncompressible ones" << std::endl;
1474 r = apply_transaction(store, &osr, std::move(t));
1475 ASSERT_EQ(r, 0);
1476
1477 struct store_statfs_t statfs;
1478 int r = store->statfs(&statfs);
1479 ASSERT_EQ(r, 0);
1480 ASSERT_EQ(0x30000 + 0x1001, statfs.stored);
1481 ASSERT_EQ(0x40000, statfs.allocated);
1482 ASSERT_LE(statfs.compressed, 0);
1483 ASSERT_EQ(0, statfs.compressed_original);
1484 ASSERT_EQ(0, statfs.compressed_allocated);
1485 //force fsck
1486 EXPECT_EQ(store->umount(), 0);
1487 EXPECT_EQ(store->mount(), 0);
1488 }
1489 {
1490 ObjectStore::Transaction t;
1491 t.zero(cid, hoid, 0, 0x40000);
1492 cerr << "Zero object" << std::endl;
1493 r = apply_transaction(store, &osr, std::move(t));
1494 ASSERT_EQ(r, 0);
1495 struct store_statfs_t statfs;
1496 int r = store->statfs(&statfs);
1497 ASSERT_EQ(r, 0);
1498 ASSERT_EQ(0u, statfs.allocated);
1499 ASSERT_EQ(0u, statfs.stored);
1500 ASSERT_EQ(0u, statfs.compressed_original);
1501 ASSERT_EQ(0u, statfs.compressed);
1502 ASSERT_EQ(0u, statfs.compressed_allocated);
1503 //force fsck
1504 EXPECT_EQ(store->umount(), 0);
1505 EXPECT_EQ(store->mount(), 0);
1506 }
1507 {
1508 ObjectStore::Transaction t;
1509 std::string s(0x10000, 'c');
1510 bufferlist bl;
1511 bl.append(s);
1512 bl.append(s);
1513 bl.append(s);
1514 bl.append(s.substr(0, 0x10000-2));
1515 t.write(cid, hoid, 0, bl.length(), bl);
1516 cerr << "Yet another compressible write" << std::endl;
1517 r = apply_transaction(store, &osr, std::move(t));
1518 ASSERT_EQ(r, 0);
1519 struct store_statfs_t statfs;
1520 r = store->statfs(&statfs);
1521 ASSERT_EQ(r, 0);
1522 ASSERT_EQ(0x40000 - 2, statfs.stored);
1523 ASSERT_EQ(0x30000, statfs.allocated);
1524 ASSERT_LE(statfs.compressed, 0x10000);
1525 ASSERT_EQ(0x20000, statfs.compressed_original);
1526 ASSERT_EQ(0x10000, statfs.compressed_allocated);
1527 //force fsck
1528 EXPECT_EQ(store->umount(), 0);
1529 EXPECT_EQ(store->mount(), 0);
1530 }
1531 {
1532 struct store_statfs_t statfs;
1533 r = store->statfs(&statfs);
1534 ASSERT_EQ(r, 0);
1535
1536 ObjectStore::Transaction t;
1537 t.clone(cid, hoid, hoid2);
1538 cerr << "Clone compressed objecte" << std::endl;
1539 r = apply_transaction(store, &osr, std::move(t));
1540 ASSERT_EQ(r, 0);
1541 struct store_statfs_t statfs2;
1542 r = store->statfs(&statfs2);
1543 ASSERT_EQ(r, 0);
1544 ASSERT_GT(statfs2.stored, statfs.stored);
1545 ASSERT_EQ(statfs2.allocated, statfs.allocated);
1546 ASSERT_GT(statfs2.compressed, statfs.compressed);
1547 ASSERT_GT(statfs2.compressed_original, statfs.compressed_original);
1548 ASSERT_EQ(statfs2.compressed_allocated, statfs.compressed_allocated);
1549 }
1550
1551 {
1552 ObjectStore::Transaction t;
1553 t.remove(cid, hoid);
1554 t.remove(cid, hoid2);
1555 t.remove_collection(cid);
1556 cerr << "Cleaning" << std::endl;
1557 r = apply_transaction(store, &osr, std::move(t));
1558 ASSERT_EQ(r, 0);
1559
1560 struct store_statfs_t statfs;
1561 r = store->statfs(&statfs);
1562 ASSERT_EQ(r, 0);
1563 ASSERT_EQ( 0u, statfs.allocated);
1564 ASSERT_EQ( 0u, statfs.stored);
1565 ASSERT_EQ( 0u, statfs.compressed_original);
1566 ASSERT_EQ( 0u, statfs.compressed);
1567 ASSERT_EQ( 0u, statfs.compressed_allocated);
1568 }
1569 g_conf->set_val("bluestore_gc_enable_total_threshold", "0");
1570 g_conf->set_val("bluestore_compression_mode", "none");
1571 g_ceph_context->_conf->apply_changes(NULL);
1572}
1573
1574TEST_P(StoreTestSpecificAUSize, BluestoreFragmentedBlobTest) {
1575 if(string(GetParam()) != "bluestore")
1576 return;
1577 StartDeferred(0x10000);
1578
1579 ObjectStore::Sequencer osr("test");
1580 int r;
1581 coll_t cid;
1582 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1583 {
1584 ObjectStore::Transaction t;
1585 t.create_collection(cid, 0);
1586 cerr << "Creating collection " << cid << std::endl;
1587 r = apply_transaction(store, &osr, std::move(t));
1588 ASSERT_EQ(r, 0);
1589 }
1590 {
1591 bool exists = store->exists(cid, hoid);
1592 ASSERT_TRUE(!exists);
1593
1594 ObjectStore::Transaction t;
1595 t.touch(cid, hoid);
1596 cerr << "Creating object " << hoid << std::endl;
1597 r = apply_transaction(store, &osr, std::move(t));
1598 ASSERT_EQ(r, 0);
1599
1600 exists = store->exists(cid, hoid);
1601 ASSERT_EQ(true, exists);
1602 }
1603 {
1604 struct store_statfs_t statfs;
1605 int r = store->statfs(&statfs);
1606 ASSERT_EQ(r, 0);
1607 ASSERT_EQ(g_conf->bluestore_block_size, statfs.total);
1608 ASSERT_EQ(0u, statfs.allocated);
1609 ASSERT_EQ(0u, statfs.stored);
1610 ASSERT_TRUE(statfs.available > 0u && statfs.available < g_conf->bluestore_block_size);
1611 }
1612 std::string data;
1613 data.resize(0x10000 * 3);
1614 {
1615 ObjectStore::Transaction t;
1616 for(size_t i = 0;i < data.size(); i++)
1617 data[i] = i / 256 + 1;
1618 bufferlist bl, newdata;
1619 bl.append(data);
1620 t.write(cid, hoid, 0, bl.length(), bl);
1621 t.zero(cid, hoid, 0x10000, 0x10000);
1622 cerr << "Append 3*0x10000 bytes and punch a hole 0x10000~10000" << std::endl;
1623 r = apply_transaction(store, &osr, std::move(t));
1624 ASSERT_EQ(r, 0);
1625
1626 struct store_statfs_t statfs;
1627 int r = store->statfs(&statfs);
1628 ASSERT_EQ(r, 0);
1629 ASSERT_EQ(0x20000, statfs.stored);
1630 ASSERT_EQ(0x20000, statfs.allocated);
1631
1632 r = store->read(cid, hoid, 0, data.size(), newdata);
1633 ASSERT_EQ(r, (int)data.size());
1634 {
1635 bufferlist expected;
1636 expected.append(data.substr(0, 0x10000));
1637 expected.append(string(0x10000, 0));
1638 expected.append(data.substr(0x20000, 0x10000));
1639 ASSERT_TRUE(bl_eq(expected, newdata));
1640 }
1641 newdata.clear();
1642
1643 r = store->read(cid, hoid, 1, data.size()-2, newdata);
1644 ASSERT_EQ(r, (int)data.size()-2);
1645 {
1646 bufferlist expected;
1647 expected.append(data.substr(1, 0x10000-1));
1648 expected.append(string(0x10000, 0));
1649 expected.append(data.substr(0x20000, 0x10000 - 1));
1650 ASSERT_TRUE(bl_eq(expected, newdata));
1651 }
1652 newdata.clear();
1653 }
1654 //force fsck
1655 EXPECT_EQ(store->umount(), 0);
1656 EXPECT_EQ(store->mount(), 0);
1657
1658 {
1659 ObjectStore::Transaction t;
1660 std::string data2(3, 'b');
1661 bufferlist bl, newdata;
1662 bl.append(data2);
1663 t.write(cid, hoid, 0x20000, bl.length(), bl);
1664 cerr << "Write 3 bytes after the hole" << std::endl;
1665 r = apply_transaction(store, &osr, std::move(t));
1666 ASSERT_EQ(r, 0);
1667
1668 struct store_statfs_t statfs;
1669 int r = store->statfs(&statfs);
1670 ASSERT_EQ(r, 0);
1671 ASSERT_EQ(0x20000, statfs.allocated);
1672 ASSERT_EQ(0x20000, statfs.stored);
1673
1674 r = store->read(cid, hoid, 0x20000-1, 21, newdata);
1675 ASSERT_EQ(r, (int)21);
1676 {
1677 bufferlist expected;
1678 expected.append(string(0x1, 0));
1679 expected.append(string(data2));
1680 expected.append(data.substr(0x20003, 21-4));
1681 ASSERT_TRUE(bl_eq(expected, newdata));
1682 }
1683 newdata.clear();
1684 }
1685 //force fsck
1686 EXPECT_EQ(store->umount(), 0);
1687 EXPECT_EQ(store->mount(), 0);
1688
1689 {
1690 ObjectStore::Transaction t;
1691 std::string data2(3, 'a');
1692 bufferlist bl, newdata;
1693 bl.append(data2);
1694 t.write(cid, hoid, 0x10000+1, bl.length(), bl);
1695 cerr << "Write 3 bytes to the hole" << std::endl;
1696 r = apply_transaction(store, &osr, std::move(t));
1697 ASSERT_EQ(r, 0);
1698
1699 struct store_statfs_t statfs;
1700 int r = store->statfs(&statfs);
1701 ASSERT_EQ(r, 0);
1702 ASSERT_EQ(0x30000, statfs.allocated);
1703 ASSERT_EQ(0x20003, statfs.stored);
1704
1705 r = store->read(cid, hoid, 0x10000-1, 0x10000+22, newdata);
1706 ASSERT_EQ(r, (int)0x10000+22);
1707 {
1708 bufferlist expected;
1709 expected.append(data.substr(0x10000-1, 1));
1710 expected.append(string(0x1, 0));
1711 expected.append(data2);
1712 expected.append(string(0x10000-4, 0));
1713 expected.append(string(0x3, 'b'));
1714 expected.append(data.substr(0x20004, 21-3));
1715 ASSERT_TRUE(bl_eq(expected, newdata));
1716 }
1717 newdata.clear();
1718 }
1719 {
1720 ObjectStore::Transaction t;
1721 bufferlist bl, newdata;
1722 bl.append(string(0x30000, 'c'));
1723 t.write(cid, hoid, 0, 0x30000, bl);
1724 t.zero(cid, hoid, 0, 0x10000);
1725 t.zero(cid, hoid, 0x20000, 0x10000);
1726 cerr << "Rewrite an object and create two holes at the begining and the end" << std::endl;
1727 r = apply_transaction(store, &osr, std::move(t));
1728 ASSERT_EQ(r, 0);
1729
1730 struct store_statfs_t statfs;
1731 int r = store->statfs(&statfs);
1732 ASSERT_EQ(r, 0);
1733 ASSERT_EQ(0x10000, statfs.allocated);
1734 ASSERT_EQ(0x10000, statfs.stored);
1735
1736 r = store->read(cid, hoid, 0, 0x30000, newdata);
1737 ASSERT_EQ(r, (int)0x30000);
1738 {
1739 bufferlist expected;
1740 expected.append(string(0x10000, 0));
1741 expected.append(string(0x10000, 'c'));
1742 expected.append(string(0x10000, 0));
1743 ASSERT_TRUE(bl_eq(expected, newdata));
1744 }
1745 newdata.clear();
1746 }
1747
1748 //force fsck
1749 EXPECT_EQ(store->umount(), 0);
1750 EXPECT_EQ(store->mount(), 0);
1751
1752 {
1753 ObjectStore::Transaction t;
1754 t.remove(cid, hoid);
1755 t.remove_collection(cid);
1756 cerr << "Cleaning" << std::endl;
1757 r = apply_transaction(store, &osr, std::move(t));
1758 ASSERT_EQ(r, 0);
1759
1760 struct store_statfs_t statfs;
1761 r = store->statfs(&statfs);
1762 ASSERT_EQ(r, 0);
1763 ASSERT_EQ( 0u, statfs.allocated);
1764 ASSERT_EQ( 0u, statfs.stored);
1765 ASSERT_EQ( 0u, statfs.compressed_original);
1766 ASSERT_EQ( 0u, statfs.compressed);
1767 ASSERT_EQ( 0u, statfs.compressed_allocated);
1768 }
1769}
1770#endif
1771
1772TEST_P(StoreTest, ManySmallWrite) {
1773 ObjectStore::Sequencer osr("test");
1774 int r;
1775 coll_t cid;
1776 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1777 ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
1778 {
1779 ObjectStore::Transaction t;
1780 t.create_collection(cid, 0);
1781 cerr << "Creating collection " << cid << std::endl;
1782 r = apply_transaction(store, &osr, std::move(t));
1783 ASSERT_EQ(r, 0);
1784 }
1785 bufferlist bl;
1786 bufferptr bp(4096);
1787 bp.zero();
1788 bl.append(bp);
1789 for (int i=0; i<100; ++i) {
1790 ObjectStore::Transaction t;
1791 t.write(cid, a, i*4096, 4096, bl, 0);
1792 r = apply_transaction(store, &osr, std::move(t));
1793 ASSERT_EQ(r, 0);
1794 }
1795 for (int i=0; i<100; ++i) {
1796 ObjectStore::Transaction t;
1797 t.write(cid, b, (rand() % 1024)*4096, 4096, bl, 0);
1798 r = apply_transaction(store, &osr, std::move(t));
1799 ASSERT_EQ(r, 0);
1800 }
1801 {
1802 ObjectStore::Transaction t;
1803 t.remove(cid, a);
1804 t.remove(cid, b);
1805 t.remove_collection(cid);
1806 cerr << "Cleaning" << std::endl;
1807 r = apply_transaction(store, &osr, std::move(t));
1808 ASSERT_EQ(r, 0);
1809 }
1810}
1811
1812TEST_P(StoreTest, MultiSmallWriteSameBlock) {
1813 ObjectStore::Sequencer osr("test");
1814 int r;
1815 coll_t cid;
1816 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1817 {
1818 ObjectStore::Transaction t;
1819 t.create_collection(cid, 0);
1820 cerr << "Creating collection " << cid << std::endl;
1821 r = apply_transaction(store, &osr, std::move(t));
1822 ASSERT_EQ(r, 0);
1823 }
1824 bufferlist bl;
1825 bl.append("short");
1826 C_SaferCond c, d;
1827 // touch same block in both same transaction, tls, and pipelined txns
1828 {
1829 ObjectStore::Transaction t, u;
1830 t.write(cid, a, 0, 5, bl, 0);
1831 t.write(cid, a, 5, 5, bl, 0);
1832 t.write(cid, a, 4094, 5, bl, 0);
1833 t.write(cid, a, 9000, 5, bl, 0);
1834 u.write(cid, a, 10, 5, bl, 0);
1835 u.write(cid, a, 7000, 5, bl, 0);
1836 vector<ObjectStore::Transaction> v = {t, u};
1837 store->queue_transactions(&osr, v, nullptr, &c);
1838 }
1839 {
1840 ObjectStore::Transaction t, u;
1841 t.write(cid, a, 40, 5, bl, 0);
1842 t.write(cid, a, 45, 5, bl, 0);
1843 t.write(cid, a, 4094, 5, bl, 0);
1844 t.write(cid, a, 6000, 5, bl, 0);
1845 u.write(cid, a, 610, 5, bl, 0);
1846 u.write(cid, a, 11000, 5, bl, 0);
1847 vector<ObjectStore::Transaction> v = {t, u};
1848 store->queue_transactions(&osr, v, nullptr, &d);
1849 }
1850 c.wait();
1851 d.wait();
1852 {
1853 bufferlist bl2;
1854 r = store->read(cid, a, 0, 16000, bl2);
1855 ASSERT_GE(r, 0);
1856 }
1857 {
1858 ObjectStore::Transaction t;
1859 t.remove(cid, a);
1860 t.remove_collection(cid);
1861 cerr << "Cleaning" << std::endl;
1862 r = apply_transaction(store, &osr, std::move(t));
1863 ASSERT_EQ(r, 0);
1864 }
1865}
1866
1867TEST_P(StoreTest, SmallSkipFront) {
1868 ObjectStore::Sequencer osr("test");
1869 int r;
1870 coll_t cid;
1871 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
1872 {
1873 ObjectStore::Transaction t;
1874 t.create_collection(cid, 0);
1875 cerr << "Creating collection " << cid << std::endl;
1876 r = apply_transaction(store, &osr, std::move(t));
1877 ASSERT_EQ(r, 0);
1878 }
1879 {
1880 ObjectStore::Transaction t;
1881 t.touch(cid, a);
1882 t.truncate(cid, a, 3000);
1883 r = apply_transaction(store, &osr, std::move(t));
1884 ASSERT_EQ(r, 0);
1885 }
1886 {
1887 bufferlist bl;
1888 bufferptr bp(4096);
1889 memset(bp.c_str(), 1, 4096);
1890 bl.append(bp);
1891 ObjectStore::Transaction t;
1892 t.write(cid, a, 4096, 4096, bl);
1893 r = apply_transaction(store, &osr, std::move(t));
1894 ASSERT_EQ(r, 0);
1895 }
1896 {
1897 bufferlist bl;
1898 ASSERT_EQ(8192, store->read(cid, a, 0, 8192, bl));
1899 for (unsigned i=0; i<4096; ++i)
1900 ASSERT_EQ(0, bl[i]);
1901 for (unsigned i=4096; i<8192; ++i)
1902 ASSERT_EQ(1, bl[i]);
1903 }
1904 {
1905 ObjectStore::Transaction t;
1906 t.remove(cid, a);
1907 t.remove_collection(cid);
1908 cerr << "Cleaning" << std::endl;
1909 r = apply_transaction(store, &osr, std::move(t));
1910 ASSERT_EQ(r, 0);
1911 }
1912}
1913
1914TEST_P(StoreTest, AppendDeferredVsTailCache) {
1915 ObjectStore::Sequencer osr("test");
1916 int r;
1917 coll_t cid;
1918 ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
1919 {
1920 ObjectStore::Transaction t;
1921 t.create_collection(cid, 0);
1922 cerr << "Creating collection " << cid << std::endl;
1923 r = store->apply_transaction(&osr, std::move(t));
1924 ASSERT_EQ(r, 0);
1925 }
1926 unsigned min_alloc = g_conf->bluestore_min_alloc_size;
1927 g_conf->set_val("bluestore_inject_deferred_apply_delay", "1.0");
1928 g_ceph_context->_conf->apply_changes(NULL);
1929 unsigned size = min_alloc / 3;
1930 bufferptr bpa(size);
1931 memset(bpa.c_str(), 1, bpa.length());
1932 bufferlist bla;
1933 bla.append(bpa);
1934 {
1935 ObjectStore::Transaction t;
1936 t.write(cid, a, 0, bla.length(), bla, 0);
1937 r = store->apply_transaction(&osr, std::move(t));
1938 ASSERT_EQ(r, 0);
1939 }
1940
1941 // force cached tail to clear ...
1942 {
1943 int r = store->umount();
1944 ASSERT_EQ(0, r);
1945 r = store->mount();
1946 ASSERT_EQ(0, r);
1947 }
1948
1949 bufferptr bpb(size);
1950 memset(bpb.c_str(), 2, bpb.length());
1951 bufferlist blb;
1952 blb.append(bpb);
1953 {
1954 ObjectStore::Transaction t;
1955 t.write(cid, a, bla.length(), blb.length(), blb, 0);
1956 r = store->apply_transaction(&osr, std::move(t));
1957 ASSERT_EQ(r, 0);
1958 }
1959 bufferptr bpc(size);
1960 memset(bpc.c_str(), 3, bpc.length());
1961 bufferlist blc;
1962 blc.append(bpc);
1963 {
1964 ObjectStore::Transaction t;
1965 t.write(cid, a, bla.length() + blb.length(), blc.length(), blc, 0);
1966 r = store->apply_transaction(&osr, std::move(t));
1967 ASSERT_EQ(r, 0);
1968 }
1969 bufferlist final;
1970 final.append(bla);
1971 final.append(blb);
1972 final.append(blc);
1973 bufferlist actual;
1974 {
1975 ASSERT_EQ((int)final.length(),
1976 store->read(cid, a, 0, final.length(), actual));
1977 ASSERT_TRUE(bl_eq(final, actual));
1978 }
1979 {
1980 ObjectStore::Transaction t;
1981 t.remove(cid, a);
1982 t.remove_collection(cid);
1983 cerr << "Cleaning" << std::endl;
1984 r = store->apply_transaction(&osr, std::move(t));
1985 ASSERT_EQ(r, 0);
1986 }
1987 g_conf->set_val("bluestore_inject_deferred_apply_delay", "0");
1988 g_ceph_context->_conf->apply_changes(NULL);
1989}
1990
1991TEST_P(StoreTest, AppendZeroTrailingSharedBlock) {
1992 ObjectStore::Sequencer osr("test");
1993 int r;
1994 coll_t cid;
1995 ghobject_t a(hobject_t(sobject_t("fooo", CEPH_NOSNAP)));
1996 ghobject_t b = a;
1997 b.hobj.snap = 1;
1998 {
1999 ObjectStore::Transaction t;
2000 t.create_collection(cid, 0);
2001 cerr << "Creating collection " << cid << std::endl;
2002 r = store->apply_transaction(&osr, std::move(t));
2003 ASSERT_EQ(r, 0);
2004 }
2005 unsigned min_alloc = g_conf->bluestore_min_alloc_size;
2006 unsigned size = min_alloc / 3;
2007 bufferptr bpa(size);
2008 memset(bpa.c_str(), 1, bpa.length());
2009 bufferlist bla;
2010 bla.append(bpa);
2011 // make sure there is some trailing gunk in the last block
2012 {
2013 bufferlist bt;
2014 bt.append(bla);
2015 bt.append("BADBADBADBAD");
2016 ObjectStore::Transaction t;
2017 t.write(cid, a, 0, bt.length(), bt, 0);
2018 r = store->apply_transaction(&osr, std::move(t));
2019 ASSERT_EQ(r, 0);
2020 }
2021 {
2022 ObjectStore::Transaction t;
2023 t.truncate(cid, a, size);
2024 r = store->apply_transaction(&osr, std::move(t));
2025 ASSERT_EQ(r, 0);
2026 }
2027
2028 // clone
2029 {
2030 ObjectStore::Transaction t;
2031 t.clone(cid, a, b);
2032 r = store->apply_transaction(&osr, std::move(t));
2033 ASSERT_EQ(r, 0);
2034 }
2035
2036 // append with implicit zeroing
2037 bufferptr bpb(size);
2038 memset(bpb.c_str(), 2, bpb.length());
2039 bufferlist blb;
2040 blb.append(bpb);
2041 {
2042 ObjectStore::Transaction t;
2043 t.write(cid, a, min_alloc * 3, blb.length(), blb, 0);
2044 r = store->apply_transaction(&osr, std::move(t));
2045 ASSERT_EQ(r, 0);
2046 }
2047 bufferlist final;
2048 final.append(bla);
2049 bufferlist zeros;
2050 zeros.append_zero(min_alloc * 3 - size);
2051 final.append(zeros);
2052 final.append(blb);
2053 bufferlist actual;
2054 {
2055 ASSERT_EQ((int)final.length(),
2056 store->read(cid, a, 0, final.length(), actual));
2057 final.hexdump(cout);
2058 actual.hexdump(cout);
2059 ASSERT_TRUE(bl_eq(final, actual));
2060 }
2061 {
2062 ObjectStore::Transaction t;
2063 t.remove(cid, a);
2064 t.remove(cid, b);
2065 t.remove_collection(cid);
2066 cerr << "Cleaning" << std::endl;
2067 r = store->apply_transaction(&osr, std::move(t));
2068 ASSERT_EQ(r, 0);
2069 }
2070}
2071
2072TEST_P(StoreTest, SmallSequentialUnaligned) {
2073 ObjectStore::Sequencer osr("test");
2074 int r;
2075 coll_t cid;
2076 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2077 {
2078 ObjectStore::Transaction t;
2079 t.create_collection(cid, 0);
2080 cerr << "Creating collection " << cid << std::endl;
2081 r = apply_transaction(store, &osr, std::move(t));
2082 ASSERT_EQ(r, 0);
2083 }
2084 bufferlist bl;
2085 int len = 1000;
2086 bufferptr bp(len);
2087 bp.zero();
2088 bl.append(bp);
2089 for (int i=0; i<1000; ++i) {
2090 ObjectStore::Transaction t;
2091 t.write(cid, a, i*len, len, bl, 0);
2092 r = apply_transaction(store, &osr, std::move(t));
2093 ASSERT_EQ(r, 0);
2094 }
2095 {
2096 ObjectStore::Transaction t;
2097 t.remove(cid, a);
2098 t.remove_collection(cid);
2099 cerr << "Cleaning" << std::endl;
2100 r = apply_transaction(store, &osr, std::move(t));
2101 ASSERT_EQ(r, 0);
2102 }
2103}
2104
2105TEST_P(StoreTest, ManyBigWrite) {
2106 ObjectStore::Sequencer osr("test");
2107 int r;
2108 coll_t cid;
2109 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2110 ghobject_t b(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
2111 {
2112 ObjectStore::Transaction t;
2113 t.create_collection(cid, 0);
2114 cerr << "Creating collection " << cid << std::endl;
2115 r = apply_transaction(store, &osr, std::move(t));
2116 ASSERT_EQ(r, 0);
2117 }
2118 bufferlist bl;
2119 bufferptr bp(4 * 1048576);
2120 bp.zero();
2121 bl.append(bp);
2122 for (int i=0; i<10; ++i) {
2123 ObjectStore::Transaction t;
2124 t.write(cid, a, i*4*1048586, 4*1048576, bl, 0);
2125 r = apply_transaction(store, &osr, std::move(t));
2126 ASSERT_EQ(r, 0);
2127 }
2128 // aligned
2129 for (int i=0; i<10; ++i) {
2130 ObjectStore::Transaction t;
2131 t.write(cid, b, (rand() % 256)*4*1048576, 4*1048576, bl, 0);
2132 r = apply_transaction(store, &osr, std::move(t));
2133 ASSERT_EQ(r, 0);
2134 }
2135 // unaligned
2136 for (int i=0; i<10; ++i) {
2137 ObjectStore::Transaction t;
2138 t.write(cid, b, (rand() % (256*4096))*1024, 4*1048576, bl, 0);
2139 r = apply_transaction(store, &osr, std::move(t));
2140 ASSERT_EQ(r, 0);
2141 }
2142 // do some zeros
2143 for (int i=0; i<10; ++i) {
2144 ObjectStore::Transaction t;
2145 t.zero(cid, b, (rand() % (256*4096))*1024, 16*1048576);
2146 r = apply_transaction(store, &osr, std::move(t));
2147 ASSERT_EQ(r, 0);
2148 }
2149 {
2150 ObjectStore::Transaction t;
2151 t.remove(cid, a);
2152 t.remove(cid, b);
2153 t.remove_collection(cid);
2154 cerr << "Cleaning" << std::endl;
2155 r = apply_transaction(store, &osr, std::move(t));
2156 ASSERT_EQ(r, 0);
2157 }
2158}
2159
2160TEST_P(StoreTest, BigWriteBigZero) {
2161 ObjectStore::Sequencer osr("test");
2162 int r;
2163 coll_t cid;
2164 ghobject_t a(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2165 {
2166 ObjectStore::Transaction t;
2167 t.create_collection(cid, 0);
2168 r = apply_transaction(store, &osr, std::move(t));
2169 ASSERT_EQ(r, 0);
2170 }
2171 bufferlist bl;
2172 bufferptr bp(1048576);
2173 memset(bp.c_str(), 'b', bp.length());
2174 bl.append(bp);
2175 bufferlist s;
2176 bufferptr sp(4096);
2177 memset(sp.c_str(), 's', sp.length());
2178 s.append(sp);
2179 {
2180 ObjectStore::Transaction t;
2181 t.write(cid, a, 0, bl.length(), bl);
2182 r = apply_transaction(store, &osr, std::move(t));
2183 ASSERT_EQ(r, 0);
2184 }
2185 {
2186 ObjectStore::Transaction t;
2187 t.zero(cid, a, bl.length() / 4, bl.length() / 2);
2188 r = apply_transaction(store, &osr, std::move(t));
2189 ASSERT_EQ(r, 0);
2190 }
2191 {
2192 ObjectStore::Transaction t;
2193 t.write(cid, a, bl.length() / 2, s.length(), s);
2194 r = apply_transaction(store, &osr, std::move(t));
2195 ASSERT_EQ(r, 0);
2196 }
2197 {
2198 ObjectStore::Transaction t;
2199 t.remove(cid, a);
2200 t.remove_collection(cid);
2201 r = apply_transaction(store, &osr, std::move(t));
2202 ASSERT_EQ(r, 0);
2203 }
2204}
2205
2206TEST_P(StoreTest, MiscFragmentTests) {
2207 ObjectStore::Sequencer osr("test");
2208 int r;
2209 coll_t cid;
2210 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
2211 {
2212 ObjectStore::Transaction t;
2213 t.create_collection(cid, 0);
2214 cerr << "Creating collection " << cid << std::endl;
2215 r = apply_transaction(store, &osr, std::move(t));
2216 ASSERT_EQ(r, 0);
2217 }
2218 bufferlist bl;
2219 bufferptr bp(524288);
2220 bp.zero();
2221 bl.append(bp);
2222 {
2223 ObjectStore::Transaction t;
2224 t.write(cid, a, 0, 524288, bl, 0);
2225 r = apply_transaction(store, &osr, std::move(t));
2226 ASSERT_EQ(r, 0);
2227 }
2228 {
2229 ObjectStore::Transaction t;
2230 t.write(cid, a, 1048576, 524288, bl, 0);
2231 r = apply_transaction(store, &osr, std::move(t));
2232 ASSERT_EQ(r, 0);
2233 }
2234 {
2235 bufferlist inbl;
2236 int r = store->read(cid, a, 524288 + 131072, 1024, inbl);
2237 ASSERT_EQ(r, 1024);
2238 ASSERT_EQ(inbl.length(), 1024u);
2239 ASSERT_TRUE(inbl.is_zero());
2240 }
2241 {
2242 ObjectStore::Transaction t;
2243 t.write(cid, a, 1048576 - 4096, 524288, bl, 0);
2244 r = apply_transaction(store, &osr, std::move(t));
2245 ASSERT_EQ(r, 0);
2246 }
2247 {
2248 ObjectStore::Transaction t;
2249 t.remove(cid, a);
2250 t.remove_collection(cid);
2251 cerr << "Cleaning" << std::endl;
2252 r = apply_transaction(store, &osr, std::move(t));
2253 ASSERT_EQ(r, 0);
2254 }
2255
2256}
2257
b32b8144
FG
2258TEST_P(StoreTest, ZeroVsObjectSize) {
2259 ObjectStore::Sequencer osr("test");
2260 int r;
2261 coll_t cid;
2262 struct stat stat;
2263 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2264 {
2265 ObjectStore::Transaction t;
2266 t.create_collection(cid, 0);
2267 cerr << "Creating collection " << cid << std::endl;
2268 r = apply_transaction(store, &osr, std::move(t));
2269 ASSERT_EQ(r, 0);
2270 }
2271 bufferlist a;
2272 a.append("stuff");
2273 {
2274 ObjectStore::Transaction t;
2275 t.write(cid, hoid, 0, 5, a);
2276 r = apply_transaction(store, &osr, std::move(t));
2277 ASSERT_EQ(r, 0);
2278 }
2279 ASSERT_EQ(0, store->stat(cid, hoid, &stat));
2280 ASSERT_EQ(5, stat.st_size);
2281 {
2282 ObjectStore::Transaction t;
2283 t.zero(cid, hoid, 1, 2);
2284 r = apply_transaction(store, &osr, std::move(t));
2285 ASSERT_EQ(r, 0);
2286 }
2287 ASSERT_EQ(0, store->stat(cid, hoid, &stat));
2288 ASSERT_EQ(5, stat.st_size);
2289 {
2290 ObjectStore::Transaction t;
2291 t.zero(cid, hoid, 3, 200);
2292 r = apply_transaction(store, &osr, std::move(t));
2293 ASSERT_EQ(r, 0);
2294 }
2295 ASSERT_EQ(0, store->stat(cid, hoid, &stat));
2296 ASSERT_EQ(203, stat.st_size);
2297 {
2298 ObjectStore::Transaction t;
2299 t.zero(cid, hoid, 100000, 200);
2300 r = apply_transaction(store, &osr, std::move(t));
2301 ASSERT_EQ(r, 0);
2302 }
2303 ASSERT_EQ(0, store->stat(cid, hoid, &stat));
2304 ASSERT_EQ(100200, stat.st_size);
2305}
2306
7c673cae
FG
2307TEST_P(StoreTest, ZeroLengthWrite) {
2308 ObjectStore::Sequencer osr("test");
2309 int r;
2310 coll_t cid;
2311 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2312 {
2313 ObjectStore::Transaction t;
2314 t.create_collection(cid, 0);
2315 t.touch(cid, hoid);
2316 r = apply_transaction(store, &osr, std::move(t));
2317 ASSERT_EQ(r, 0);
2318 }
2319 {
2320 ObjectStore::Transaction t;
2321 bufferlist empty;
2322 t.write(cid, hoid, 1048576, 0, empty);
2323 r = apply_transaction(store, &osr, std::move(t));
2324 ASSERT_EQ(r, 0);
2325 }
2326 struct stat stat;
2327 r = store->stat(cid, hoid, &stat);
2328 ASSERT_EQ(0, r);
2329 ASSERT_EQ(0, stat.st_size);
2330
2331 bufferlist newdata;
2332 r = store->read(cid, hoid, 0, 1048576, newdata);
2333 ASSERT_EQ(0, r);
2334}
2335
b32b8144
FG
2336TEST_P(StoreTest, ZeroLengthZero) {
2337 ObjectStore::Sequencer osr("test");
2338 int r;
2339 coll_t cid;
2340 ghobject_t hoid(hobject_t(sobject_t("foo", CEPH_NOSNAP)));
2341 {
2342 ObjectStore::Transaction t;
2343 t.create_collection(cid, 0);
2344 t.touch(cid, hoid);
2345 r = apply_transaction(store, &osr, std::move(t));
2346 ASSERT_EQ(0, r);
2347 }
2348 {
2349 ObjectStore::Transaction t;
2350 t.zero(cid, hoid, 1048576, 0);
2351 r = apply_transaction(store, &osr, std::move(t));
2352 ASSERT_EQ(0, r);
2353 }
2354 struct stat stat;
2355 r = store->stat(cid, hoid, &stat);
2356 ASSERT_EQ(0, r);
2357 ASSERT_EQ(0, stat.st_size);
2358
2359 bufferlist newdata;
2360 r = store->read(cid, hoid, 0, 1048576, newdata);
2361 ASSERT_EQ(0, r);
2362}
2363
7c673cae
FG
2364TEST_P(StoreTest, SimpleAttrTest) {
2365 ObjectStore::Sequencer osr("test");
2366 int r;
2367 coll_t cid;
2368 ghobject_t hoid(hobject_t(sobject_t("attr object 1", CEPH_NOSNAP)));
2369 bufferlist val, val2;
2370 val.append("value");
2371 val.append("value2");
2372 {
2373 bufferptr bp;
2374 map<string,bufferptr> aset;
2375 r = store->getattr(cid, hoid, "nofoo", bp);
2376 ASSERT_EQ(-ENOENT, r);
2377 r = store->getattrs(cid, hoid, aset);
2378 ASSERT_EQ(-ENOENT, r);
2379 }
2380 {
2381 ObjectStore::Transaction t;
2382 t.create_collection(cid, 0);
2383 r = apply_transaction(store, &osr, std::move(t));
2384 ASSERT_EQ(r, 0);
2385 }
b32b8144 2386 osr.flush();
7c673cae
FG
2387 {
2388 bool empty;
2389 int r = store->collection_empty(cid, &empty);
2390 ASSERT_EQ(0, r);
2391 ASSERT_TRUE(empty);
2392 }
2393 {
2394 bufferptr bp;
2395 r = store->getattr(cid, hoid, "nofoo", bp);
2396 ASSERT_EQ(-ENOENT, r);
2397 }
2398 {
2399 ObjectStore::Transaction t;
2400 t.touch(cid, hoid);
2401 t.setattr(cid, hoid, "foo", val);
2402 t.setattr(cid, hoid, "bar", val2);
2403 r = apply_transaction(store, &osr, std::move(t));
2404 ASSERT_EQ(r, 0);
2405 }
b32b8144 2406 osr.flush();
7c673cae
FG
2407 {
2408 bool empty;
2409 int r = store->collection_empty(cid, &empty);
2410 ASSERT_EQ(0, r);
2411 ASSERT_TRUE(!empty);
2412 }
2413 {
2414 bufferptr bp;
2415 r = store->getattr(cid, hoid, "nofoo", bp);
2416 ASSERT_EQ(-ENODATA, r);
2417
2418 r = store->getattr(cid, hoid, "foo", bp);
2419 ASSERT_EQ(0, r);
2420 bufferlist bl;
2421 bl.append(bp);
2422 ASSERT_TRUE(bl_eq(val, bl));
2423
2424 map<string,bufferptr> bm;
2425 r = store->getattrs(cid, hoid, bm);
2426 ASSERT_EQ(0, r);
2427
2428 }
2429 {
2430 ObjectStore::Transaction t;
2431 t.remove(cid, hoid);
2432 t.remove_collection(cid);
2433 r = apply_transaction(store, &osr, std::move(t));
2434 ASSERT_EQ(r, 0);
2435 }
2436}
2437
2438TEST_P(StoreTest, SimpleListTest) {
2439 ObjectStore::Sequencer osr("test");
2440 int r;
2441 coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2442 {
2443 ObjectStore::Transaction t;
2444 t.create_collection(cid, 0);
2445 cerr << "Creating collection " << cid << std::endl;
2446 r = apply_transaction(store, &osr, std::move(t));
2447 ASSERT_EQ(r, 0);
2448 }
2449 set<ghobject_t> all;
2450 {
2451 ObjectStore::Transaction t;
2452 for (int i=0; i<200; ++i) {
2453 string name("object_");
2454 name += stringify(i);
2455 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
2456 ghobject_t::NO_GEN, shard_id_t(1));
2457 hoid.hobj.pool = 1;
2458 all.insert(hoid);
2459 t.touch(cid, hoid);
2460 cerr << "Creating object " << hoid << std::endl;
2461 }
2462 r = apply_transaction(store, &osr, std::move(t));
2463 ASSERT_EQ(r, 0);
2464 }
2465 {
2466 set<ghobject_t> saw;
2467 vector<ghobject_t> objects;
2468 ghobject_t next, current;
2469 while (!next.is_max()) {
2470 int r = store->collection_list(cid, current, ghobject_t::get_max(),
2471 50,
2472 &objects, &next);
2473 ASSERT_EQ(r, 0);
2474 ASSERT_TRUE(sorted(objects));
2475 cout << " got " << objects.size() << " next " << next << std::endl;
2476 for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
2477 ++p) {
2478 if (saw.count(*p)) {
2479 cout << "got DUP " << *p << std::endl;
2480 } else {
2481 //cout << "got new " << *p << std::endl;
2482 }
2483 saw.insert(*p);
2484 }
2485 objects.clear();
2486 current = next;
2487 }
2488 ASSERT_EQ(saw.size(), all.size());
2489 ASSERT_EQ(saw, all);
2490 }
2491 {
2492 ObjectStore::Transaction t;
2493 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2494 t.remove(cid, *p);
2495 t.remove_collection(cid);
2496 cerr << "Cleaning" << std::endl;
2497 r = apply_transaction(store, &osr, std::move(t));
2498 ASSERT_EQ(r, 0);
2499 }
2500}
2501
2502TEST_P(StoreTest, ListEndTest) {
2503 ObjectStore::Sequencer osr("test");
2504 int r;
2505 coll_t cid(spg_t(pg_t(0, 1), shard_id_t(1)));
2506 {
2507 ObjectStore::Transaction t;
2508 t.create_collection(cid, 0);
2509 cerr << "Creating collection " << cid << std::endl;
2510 r = apply_transaction(store, &osr, std::move(t));
2511 ASSERT_EQ(r, 0);
2512 }
2513 set<ghobject_t> all;
2514 {
2515 ObjectStore::Transaction t;
2516 for (int i=0; i<200; ++i) {
2517 string name("object_");
2518 name += stringify(i);
2519 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)),
2520 ghobject_t::NO_GEN, shard_id_t(1));
2521 hoid.hobj.pool = 1;
2522 all.insert(hoid);
2523 t.touch(cid, hoid);
2524 cerr << "Creating object " << hoid << std::endl;
2525 }
2526 r = apply_transaction(store, &osr, std::move(t));
2527 ASSERT_EQ(r, 0);
2528 }
2529 {
2530 ghobject_t end(hobject_t(sobject_t("object_100", CEPH_NOSNAP)),
2531 ghobject_t::NO_GEN, shard_id_t(1));
2532 end.hobj.pool = 1;
2533 vector<ghobject_t> objects;
2534 ghobject_t next;
2535 int r = store->collection_list(cid, ghobject_t(), end, 500,
2536 &objects, &next);
2537 ASSERT_EQ(r, 0);
2538 for (auto &p : objects) {
2539 ASSERT_NE(p, end);
2540 }
2541 }
2542 {
2543 ObjectStore::Transaction t;
2544 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2545 t.remove(cid, *p);
2546 t.remove_collection(cid);
2547 cerr << "Cleaning" << std::endl;
2548 r = apply_transaction(store, &osr, std::move(t));
2549 ASSERT_EQ(r, 0);
2550 }
2551}
2552
2553TEST_P(StoreTest, Sort) {
2554 {
2555 hobject_t a(sobject_t("a", CEPH_NOSNAP));
2556 hobject_t b = a;
2557 ASSERT_EQ(a, b);
2558 b.oid.name = "b";
2559 ASSERT_NE(a, b);
2560 ASSERT_TRUE(a < b);
2561 a.pool = 1;
2562 b.pool = 2;
2563 ASSERT_TRUE(a < b);
2564 a.pool = 3;
2565 ASSERT_TRUE(a > b);
2566 }
2567 {
2568 ghobject_t a(hobject_t(sobject_t("a", CEPH_NOSNAP)));
2569 ghobject_t b(hobject_t(sobject_t("b", CEPH_NOSNAP)));
2570 a.hobj.pool = 1;
2571 b.hobj.pool = 1;
2572 ASSERT_TRUE(a < b);
2573 a.hobj.pool = -3;
2574 ASSERT_TRUE(a < b);
2575 a.hobj.pool = 1;
2576 b.hobj.pool = -3;
2577 ASSERT_TRUE(a > b);
2578 }
2579}
2580
2581TEST_P(StoreTest, MultipoolListTest) {
2582 ObjectStore::Sequencer osr("test");
2583 int r;
2584 int poolid = 4373;
2585 coll_t cid = coll_t(spg_t(pg_t(0, poolid), shard_id_t::NO_SHARD));
2586 {
2587 ObjectStore::Transaction t;
2588 t.create_collection(cid, 0);
2589 cerr << "Creating collection " << cid << std::endl;
2590 r = apply_transaction(store, &osr, std::move(t));
2591 ASSERT_EQ(r, 0);
2592 }
2593 set<ghobject_t> all, saw;
2594 {
2595 ObjectStore::Transaction t;
2596 for (int i=0; i<200; ++i) {
2597 string name("object_");
2598 name += stringify(i);
2599 ghobject_t hoid(hobject_t(sobject_t(name, CEPH_NOSNAP)));
2600 if (rand() & 1)
2601 hoid.hobj.pool = -2 - poolid;
2602 else
2603 hoid.hobj.pool = poolid;
2604 all.insert(hoid);
2605 t.touch(cid, hoid);
2606 cerr << "Creating object " << hoid << std::endl;
2607 }
2608 r = apply_transaction(store, &osr, std::move(t));
2609 ASSERT_EQ(r, 0);
2610 }
2611 {
2612 vector<ghobject_t> objects;
2613 ghobject_t next, current;
2614 while (!next.is_max()) {
2615 int r = store->collection_list(cid, current, ghobject_t::get_max(), 50,
2616 &objects, &next);
2617 ASSERT_EQ(r, 0);
2618 cout << " got " << objects.size() << " next " << next << std::endl;
2619 for (vector<ghobject_t>::iterator p = objects.begin(); p != objects.end();
2620 ++p) {
2621 saw.insert(*p);
2622 }
2623 objects.clear();
2624 current = next;
2625 }
2626 ASSERT_EQ(saw, all);
2627 }
2628 {
2629 ObjectStore::Transaction t;
2630 for (set<ghobject_t>::iterator p = all.begin(); p != all.end(); ++p)
2631 t.remove(cid, *p);
2632 t.remove_collection(cid);
2633 cerr << "Cleaning" << std::endl;
2634 r = apply_transaction(store, &osr, std::move(t));
2635 ASSERT_EQ(r, 0);
2636 }
2637}
2638
2639TEST_P(StoreTest, SimpleCloneTest) {
2640 ObjectStore::Sequencer osr("test");
2641 int r;
2642 coll_t cid;
2643 {
2644 ObjectStore::Transaction t;
2645 t.create_collection(cid, 0);
2646 cerr << "Creating collection " << cid << std::endl;
2647 r = apply_transaction(store, &osr, std::move(t));
2648 ASSERT_EQ(r, 0);
2649 }
2650 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
2651 "key", 123, -1, ""));
2652 bufferlist small, large, xlarge, newdata, attr;
2653 small.append("small");
2654 large.append("large");
2655 xlarge.append("xlarge");
2656 {
2657 ObjectStore::Transaction t;
2658 t.touch(cid, hoid);
2659 t.setattr(cid, hoid, "attr1", small);
2660 t.setattr(cid, hoid, "attr2", large);
2661 t.setattr(cid, hoid, "attr3", xlarge);
2662 t.write(cid, hoid, 0, small.length(), small);
2663 t.write(cid, hoid, 10, small.length(), small);
2664 cerr << "Creating object and set attr " << hoid << std::endl;
2665 r = apply_transaction(store, &osr, std::move(t));
2666 ASSERT_EQ(r, 0);
2667 }
2668
2669 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
2670 "key", 123, -1, ""));
2671 ghobject_t hoid3(hobject_t(sobject_t("Object 3", CEPH_NOSNAP)));
2672 {
2673 ObjectStore::Transaction t;
2674 t.clone(cid, hoid, hoid2);
2675 t.setattr(cid, hoid2, "attr2", small);
2676 t.rmattr(cid, hoid2, "attr1");
2677 t.write(cid, hoid, 10, large.length(), large);
2678 t.setattr(cid, hoid, "attr1", large);
2679 t.setattr(cid, hoid, "attr2", small);
2680 cerr << "Clone object and rm attr" << std::endl;
2681 r = apply_transaction(store, &osr, std::move(t));
2682 ASSERT_EQ(r, 0);
2683
2684 r = store->read(cid, hoid, 10, 5, newdata);
2685 ASSERT_EQ(r, 5);
2686 ASSERT_TRUE(bl_eq(large, newdata));
2687
2688 newdata.clear();
2689 r = store->read(cid, hoid, 0, 5, newdata);
2690 ASSERT_EQ(r, 5);
2691 ASSERT_TRUE(bl_eq(small, newdata));
2692
2693 newdata.clear();
2694 r = store->read(cid, hoid2, 10, 5, newdata);
2695 ASSERT_EQ(r, 5);
2696 ASSERT_TRUE(bl_eq(small, newdata));
2697
2698 r = store->getattr(cid, hoid2, "attr2", attr);
2699 ASSERT_EQ(r, 0);
2700 ASSERT_TRUE(bl_eq(small, attr));
2701
2702 attr.clear();
2703 r = store->getattr(cid, hoid2, "attr3", attr);
2704 ASSERT_EQ(r, 0);
2705 ASSERT_TRUE(bl_eq(xlarge, attr));
2706
2707 attr.clear();
2708 r = store->getattr(cid, hoid, "attr1", attr);
2709 ASSERT_EQ(r, 0);
2710 ASSERT_TRUE(bl_eq(large, attr));
2711 }
2712 {
2713 ObjectStore::Transaction t;
2714 t.remove(cid, hoid);
2715 t.remove(cid, hoid2);
2716 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2717 }
2718 {
2719 bufferlist final;
2720 bufferptr p(16384);
2721 memset(p.c_str(), 1, p.length());
2722 bufferlist pl;
2723 pl.append(p);
2724 final.append(p);
2725 ObjectStore::Transaction t;
2726 t.write(cid, hoid, 0, pl.length(), pl);
2727 t.clone(cid, hoid, hoid2);
2728 bufferptr a(4096);
2729 memset(a.c_str(), 2, a.length());
2730 bufferlist al;
2731 al.append(a);
2732 final.append(a);
2733 t.write(cid, hoid, pl.length(), a.length(), al);
2734 r = apply_transaction(store, &osr, std::move(t));
2735 ASSERT_EQ(r, 0);
2736 bufferlist rl;
2737 ASSERT_EQ((int)final.length(),
2738 store->read(cid, hoid, 0, final.length(), rl));
2739 ASSERT_TRUE(bl_eq(rl, final));
2740 }
2741 {
2742 ObjectStore::Transaction t;
2743 t.remove(cid, hoid);
2744 t.remove(cid, hoid2);
2745 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2746 }
2747 {
2748 bufferlist final;
2749 bufferptr p(16384);
2750 memset(p.c_str(), 111, p.length());
2751 bufferlist pl;
2752 pl.append(p);
2753 final.append(p);
2754 ObjectStore::Transaction t;
2755 t.write(cid, hoid, 0, pl.length(), pl);
2756 t.clone(cid, hoid, hoid2);
2757 bufferptr z(4096);
2758 z.zero();
2759 final.append(z);
2760 bufferptr a(4096);
2761 memset(a.c_str(), 112, a.length());
2762 bufferlist al;
2763 al.append(a);
2764 final.append(a);
2765 t.write(cid, hoid, pl.length() + z.length(), a.length(), al);
2766 r = apply_transaction(store, &osr, std::move(t));
2767 ASSERT_EQ(r, 0);
2768 bufferlist rl;
2769 ASSERT_EQ((int)final.length(),
2770 store->read(cid, hoid, 0, final.length(), rl));
2771 ASSERT_TRUE(bl_eq(rl, final));
2772 }
2773 {
2774 ObjectStore::Transaction t;
2775 t.remove(cid, hoid);
2776 t.remove(cid, hoid2);
2777 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2778 }
2779 {
2780 bufferlist final;
2781 bufferptr p(16000);
2782 memset(p.c_str(), 5, p.length());
2783 bufferlist pl;
2784 pl.append(p);
2785 final.append(p);
2786 ObjectStore::Transaction t;
2787 t.write(cid, hoid, 0, pl.length(), pl);
2788 t.clone(cid, hoid, hoid2);
2789 bufferptr z(1000);
2790 z.zero();
2791 final.append(z);
2792 bufferptr a(8000);
2793 memset(a.c_str(), 6, a.length());
2794 bufferlist al;
2795 al.append(a);
2796 final.append(a);
2797 t.write(cid, hoid, 17000, a.length(), al);
2798 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2799 bufferlist rl;
2800 ASSERT_EQ((int)final.length(),
2801 store->read(cid, hoid, 0, final.length(), rl));
2802 /*cout << "expected:\n";
2803 final.hexdump(cout);
2804 cout << "got:\n";
2805 rl.hexdump(cout);*/
2806 ASSERT_TRUE(bl_eq(rl, final));
2807 }
2808 {
2809 ObjectStore::Transaction t;
2810 t.remove(cid, hoid);
2811 t.remove(cid, hoid2);
2812 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2813 }
2814 {
2815 bufferptr p(1048576);
2816 memset(p.c_str(), 3, p.length());
2817 bufferlist pl;
2818 pl.append(p);
2819 ObjectStore::Transaction t;
2820 t.write(cid, hoid, 0, pl.length(), pl);
2821 t.clone(cid, hoid, hoid2);
2822 bufferptr a(65536);
2823 memset(a.c_str(), 4, a.length());
2824 bufferlist al;
2825 al.append(a);
2826 t.write(cid, hoid, a.length(), a.length(), al);
2827 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2828 bufferlist rl;
2829 bufferlist final;
2830 final.substr_of(pl, 0, al.length());
2831 final.append(al);
2832 bufferlist end;
2833 end.substr_of(pl, al.length()*2, pl.length() - al.length()*2);
2834 final.append(end);
2835 ASSERT_EQ((int)final.length(),
2836 store->read(cid, hoid, 0, final.length(), rl));
2837 /*cout << "expected:\n";
2838 final.hexdump(cout);
2839 cout << "got:\n";
2840 rl.hexdump(cout);*/
2841 ASSERT_TRUE(bl_eq(rl, final));
2842 }
2843 {
2844 ObjectStore::Transaction t;
2845 t.remove(cid, hoid);
2846 t.remove(cid, hoid2);
2847 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2848 }
2849 {
2850 bufferptr p(65536);
2851 memset(p.c_str(), 7, p.length());
2852 bufferlist pl;
2853 pl.append(p);
2854 ObjectStore::Transaction t;
2855 t.write(cid, hoid, 0, pl.length(), pl);
2856 t.clone(cid, hoid, hoid2);
2857 bufferptr a(4096);
2858 memset(a.c_str(), 8, a.length());
2859 bufferlist al;
2860 al.append(a);
2861 t.write(cid, hoid, 32768, a.length(), al);
2862 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2863 bufferlist rl;
2864 bufferlist final;
2865 final.substr_of(pl, 0, 32768);
2866 final.append(al);
2867 bufferlist end;
2868 end.substr_of(pl, final.length(), pl.length() - final.length());
2869 final.append(end);
2870 ASSERT_EQ((int)final.length(),
2871 store->read(cid, hoid, 0, final.length(), rl));
2872 /*cout << "expected:\n";
2873 final.hexdump(cout);
2874 cout << "got:\n";
2875 rl.hexdump(cout);*/
2876 ASSERT_TRUE(bl_eq(rl, final));
2877 }
2878 {
2879 ObjectStore::Transaction t;
2880 t.remove(cid, hoid);
2881 t.remove(cid, hoid2);
2882 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2883 }
2884 {
2885 bufferptr p(65536);
2886 memset(p.c_str(), 9, p.length());
2887 bufferlist pl;
2888 pl.append(p);
2889 ObjectStore::Transaction t;
2890 t.write(cid, hoid, 0, pl.length(), pl);
2891 t.clone(cid, hoid, hoid2);
2892 bufferptr a(4096);
2893 memset(a.c_str(), 10, a.length());
2894 bufferlist al;
2895 al.append(a);
2896 t.write(cid, hoid, 33768, a.length(), al);
2897 ASSERT_EQ(0, apply_transaction(store, &osr, std::move(t)));
2898 bufferlist rl;
2899 bufferlist final;
2900 final.substr_of(pl, 0, 33768);
2901 final.append(al);
2902 bufferlist end;
2903 end.substr_of(pl, final.length(), pl.length() - final.length());
2904 final.append(end);
2905 ASSERT_EQ((int)final.length(),
2906 store->read(cid, hoid, 0, final.length(), rl));
2907 /*cout << "expected:\n";
2908 final.hexdump(cout);
2909 cout << "got:\n";
2910 rl.hexdump(cout);*/
2911 ASSERT_TRUE(bl_eq(rl, final));
2912 }
2913
2914 //Unfortunately we need a workaround for filestore since EXPECT_DEATH
2915 // macro has potential issues when using /in multithread environments.
2916 //It works well for all stores but filestore for now.
2917 //A fix setting gtest_death_test_style = "threadsafe" doesn't help as well -
2918 // test app clone asserts on store folder presence.
2919 //
2920 if (string(GetParam()) != "filestore") {
2921 //verify if non-empty collection is properly handled after store reload
2922 r = store->umount();
2923 ASSERT_EQ(r, 0);
2924 r = store->mount();
2925 ASSERT_EQ(r, 0);
2926
2927 ObjectStore::Transaction t;
2928 t.remove_collection(cid);
2929 cerr << "Invalid rm coll" << std::endl;
2930 PrCtl unset_dumpable;
35e4c445 2931 EXPECT_DEATH(apply_transaction(store, &osr, std::move(t)), "");
7c673cae
FG
2932 }
2933 {
2934 ObjectStore::Transaction t;
2935 t.touch(cid, hoid3); //new record in db
2936 r = apply_transaction(store, &osr, std::move(t));
2937 ASSERT_EQ(r, 0);
2938 }
2939 //See comment above for "filestore" check explanation.
2940 if (string(GetParam()) != "filestore") {
2941 ObjectStore::Transaction t;
2942 //verify if non-empty collection is properly handled when there are some pending removes and live records in db
2943 cerr << "Invalid rm coll again" << std::endl;
2944 r = store->umount();
2945 ASSERT_EQ(r, 0);
2946 r = store->mount();
2947 ASSERT_EQ(r, 0);
2948
2949 t.remove(cid, hoid);
2950 t.remove(cid, hoid2);
2951 t.remove_collection(cid);
2952 PrCtl unset_dumpable;
35e4c445 2953 EXPECT_DEATH(apply_transaction(store, &osr, std::move(t)), "");
7c673cae
FG
2954 }
2955 {
2956 ObjectStore::Transaction t;
2957 t.remove(cid, hoid);
2958 t.remove(cid, hoid2);
2959 t.remove(cid, hoid3);
2960 t.remove_collection(cid);
2961 cerr << "Cleaning" << std::endl;
2962 r = apply_transaction(store, &osr, std::move(t));
2963 ASSERT_EQ(r, 0);
2964 }
2965}
2966
2967TEST_P(StoreTest, OmapSimple) {
2968 ObjectStore::Sequencer osr("test");
2969 int r;
2970 coll_t cid;
2971 {
2972 ObjectStore::Transaction t;
2973 t.create_collection(cid, 0);
2974 cerr << "Creating collection " << cid << std::endl;
2975 r = apply_transaction(store, &osr, std::move(t));
2976 ASSERT_EQ(r, 0);
2977 }
2978 ghobject_t hoid(hobject_t(sobject_t("omap_obj", CEPH_NOSNAP),
2979 "key", 123, -1, ""));
2980 bufferlist small;
2981 small.append("small");
2982 map<string,bufferlist> km;
2983 km["foo"] = small;
2984 km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
2985 bufferlist header;
2986 header.append("this is a header");
2987 {
2988 ObjectStore::Transaction t;
2989 t.touch(cid, hoid);
2990 t.omap_setkeys(cid, hoid, km);
2991 t.omap_setheader(cid, hoid, header);
2992 cerr << "Creating object and set omap " << hoid << std::endl;
2993 r = apply_transaction(store, &osr, std::move(t));
2994 ASSERT_EQ(r, 0);
2995 }
2996 // get header, keys
2997 {
2998 bufferlist h;
2999 map<string,bufferlist> r;
3000 store->omap_get(cid, hoid, &h, &r);
3001 ASSERT_TRUE(bl_eq(header, h));
3002 ASSERT_EQ(r.size(), km.size());
3003 cout << "r: " << r << std::endl;
3004 }
3005 // test iterator with seek_to_first
3006 {
3007 map<string,bufferlist> r;
3008 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(cid, hoid);
3009 for (iter->seek_to_first(); iter->valid(); iter->next(false)) {
3010 r[iter->key()] = iter->value();
3011 }
3012 cout << "r: " << r << std::endl;
3013 ASSERT_EQ(r.size(), km.size());
3014 }
3015 // test iterator with initial lower_bound
3016 {
3017 map<string,bufferlist> r;
3018 ObjectMap::ObjectMapIterator iter = store->get_omap_iterator(cid, hoid);
3019 for (iter->lower_bound(string()); iter->valid(); iter->next(false)) {
3020 r[iter->key()] = iter->value();
3021 }
3022 cout << "r: " << r << std::endl;
3023 ASSERT_EQ(r.size(), km.size());
3024 }
3025 {
3026 ObjectStore::Transaction t;
3027 t.remove(cid, hoid);
3028 t.remove_collection(cid);
3029 cerr << "Cleaning" << std::endl;
3030 r = apply_transaction(store, &osr, std::move(t));
3031 ASSERT_EQ(r, 0);
3032 }
3033}
3034
3035TEST_P(StoreTest, OmapCloneTest) {
3036 ObjectStore::Sequencer osr("test");
3037 int r;
3038 coll_t cid;
3039 {
3040 ObjectStore::Transaction t;
3041 t.create_collection(cid, 0);
3042 cerr << "Creating collection " << cid << std::endl;
3043 r = apply_transaction(store, &osr, std::move(t));
3044 ASSERT_EQ(r, 0);
3045 }
3046 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP),
3047 "key", 123, -1, ""));
3048 bufferlist small;
3049 small.append("small");
3050 map<string,bufferlist> km;
3051 km["foo"] = small;
3052 km["bar"].append("asdfjkasdkjdfsjkafskjsfdj");
3053 bufferlist header;
3054 header.append("this is a header");
3055 {
3056 ObjectStore::Transaction t;
3057 t.touch(cid, hoid);
3058 t.omap_setkeys(cid, hoid, km);
3059 t.omap_setheader(cid, hoid, header);
3060 cerr << "Creating object and set omap " << hoid << std::endl;
3061 r = apply_transaction(store, &osr, std::move(t));
3062 ASSERT_EQ(r, 0);
3063 }
3064 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP),
3065 "key", 123, -1, ""));
3066 {
3067 ObjectStore::Transaction t;
3068 t.clone(cid, hoid, hoid2);
3069 cerr << "Clone object" << std::endl;
3070 r = apply_transaction(store, &osr, std::move(t));
3071 ASSERT_EQ(r, 0);
3072 }
3073 {
3074 map<string,bufferlist> r;
3075 bufferlist h;
3076 store->omap_get(cid, hoid2, &h, &r);
3077 ASSERT_TRUE(bl_eq(header, h));
3078 ASSERT_EQ(r.size(), km.size());
3079 }
3080 {
3081 ObjectStore::Transaction t;
3082 t.remove(cid, hoid);
3083 t.remove(cid, hoid2);
3084 t.remove_collection(cid);
3085 cerr << "Cleaning" << std::endl;
3086 r = apply_transaction(store, &osr, std::move(t));
3087 ASSERT_EQ(r, 0);
3088 }
3089}
3090
3091TEST_P(StoreTest, SimpleCloneRangeTest) {
3092 ObjectStore::Sequencer osr("test");
3093 int r;
3094 coll_t cid;
3095 {
3096 ObjectStore::Transaction t;
3097 t.create_collection(cid, 0);
3098 cerr << "Creating collection " << cid << std::endl;
3099 r = apply_transaction(store, &osr, std::move(t));
3100 ASSERT_EQ(r, 0);
3101 }
3102 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
3103 hoid.hobj.pool = -1;
3104 bufferlist small, newdata;
3105 small.append("small");
3106 {
3107 ObjectStore::Transaction t;
3108 t.write(cid, hoid, 10, 5, small);
3109 cerr << "Creating object and write bl " << hoid << std::endl;
3110 r = apply_transaction(store, &osr, std::move(t));
3111 ASSERT_EQ(r, 0);
3112 }
3113 ghobject_t hoid2(hobject_t(sobject_t("Object 2", CEPH_NOSNAP)));
3114 hoid2.hobj.pool = -1;
3115 {
3116 ObjectStore::Transaction t;
3117 t.clone_range(cid, hoid, hoid2, 10, 5, 10);
3118 cerr << "Clone range object" << std::endl;
3119 r = apply_transaction(store, &osr, std::move(t));
3120 ASSERT_EQ(r, 0);
3121 r = store->read(cid, hoid2, 10, 5, newdata);
3122 ASSERT_EQ(r, 5);
3123 ASSERT_TRUE(bl_eq(small, newdata));
3124 }
3125 {
3126 ObjectStore::Transaction t;
3127 t.truncate(cid, hoid, 1024*1024);
3128 t.clone_range(cid, hoid, hoid2, 0, 1024*1024, 0);
3129 cerr << "Clone range object" << std::endl;
3130 r = apply_transaction(store, &osr, std::move(t));
3131 ASSERT_EQ(r, 0);
3132 struct stat stat, stat2;
3133 r = store->stat(cid, hoid, &stat);
3134 r = store->stat(cid, hoid2, &stat2);
3135 ASSERT_EQ(stat.st_size, stat2.st_size);
3136 ASSERT_EQ(1024*1024, stat2.st_size);
3137 }
3138 {
3139 ObjectStore::Transaction t;
3140 t.remove(cid, hoid);
3141 t.remove(cid, hoid2);
3142 t.remove_collection(cid);
3143 cerr << "Cleaning" << std::endl;
3144 r = apply_transaction(store, &osr, std::move(t));
3145 ASSERT_EQ(r, 0);
3146 }
3147}
3148
3149
3150TEST_P(StoreTest, SimpleObjectLongnameTest) {
3151 ObjectStore::Sequencer osr("test");
3152 int r;
3153 coll_t cid;
3154 {
3155 ObjectStore::Transaction t;
3156 t.create_collection(cid, 0);
3157 cerr << "Creating collection " << cid << std::endl;
3158 r = apply_transaction(store, &osr, std::move(t));
3159 ASSERT_EQ(r, 0);
3160 }
3161 ghobject_t hoid(hobject_t(sobject_t("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaObjectaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1", CEPH_NOSNAP)));
3162 {
3163 ObjectStore::Transaction t;
3164 t.touch(cid, hoid);
3165 cerr << "Creating object " << hoid << std::endl;
3166 r = apply_transaction(store, &osr, std::move(t));
3167 ASSERT_EQ(r, 0);
3168 }
3169 {
3170 ObjectStore::Transaction t;
3171 t.remove(cid, hoid);
3172 t.remove_collection(cid);
3173 cerr << "Cleaning" << std::endl;
3174 r = apply_transaction(store, &osr, std::move(t));
3175 ASSERT_EQ(r, 0);
3176 }
3177}
3178
3179ghobject_t generate_long_name(unsigned i)
3180{
3181 stringstream name;
3182 name << "object id " << i << " ";
3183 for (unsigned j = 0; j < 500; ++j) name << 'a';
3184 ghobject_t hoid(hobject_t(sobject_t(name.str(), CEPH_NOSNAP)));
3185 hoid.hobj.set_hash(i % 2);
3186 return hoid;
3187}
3188
3189TEST_P(StoreTest, LongnameSplitTest) {
3190 ObjectStore::Sequencer osr("test");
3191 int r;
3192 coll_t cid;
3193 {
3194 ObjectStore::Transaction t;
3195 t.create_collection(cid, 0);
3196 cerr << "Creating collection " << cid << std::endl;
3197 r = apply_transaction(store, &osr, std::move(t));
3198 ASSERT_EQ(0, r);
3199 }
3200 for (unsigned i = 0; i < 320; ++i) {
3201 ObjectStore::Transaction t;
3202 ghobject_t hoid = generate_long_name(i);
3203 t.touch(cid, hoid);
3204 cerr << "Creating object " << hoid << std::endl;
3205 r = apply_transaction(store, &osr, std::move(t));
3206 ASSERT_EQ(0, r);
3207 }
3208
3209 ghobject_t test_obj = generate_long_name(319);
3210 ghobject_t test_obj_2 = test_obj;
3211 test_obj_2.generation = 0;
3212 {
3213 ObjectStore::Transaction t;
3214 // should cause a split
3215 t.collection_move_rename(
3216 cid, test_obj,
3217 cid, test_obj_2);
3218 r = apply_transaction(store, &osr, std::move(t));
3219 ASSERT_EQ(0, r);
3220 }
3221
3222 for (unsigned i = 0; i < 319; ++i) {
3223 ObjectStore::Transaction t;
3224 ghobject_t hoid = generate_long_name(i);
3225 t.remove(cid, hoid);
3226 cerr << "Removing object " << hoid << std::endl;
3227 r = apply_transaction(store, &osr, std::move(t));
3228 ASSERT_EQ(0, r);
3229 }
3230 {
3231 ObjectStore::Transaction t;
3232 t.remove(cid, test_obj_2);
3233 t.remove_collection(cid);
3234 cerr << "Cleaning" << std::endl;
3235 r = apply_transaction(store, &osr, std::move(t));
3236 ASSERT_EQ(0, r);
3237 }
3238
3239}
3240
3241TEST_P(StoreTest, ManyObjectTest) {
3242 ObjectStore::Sequencer osr("test");
3243 int NUM_OBJS = 2000;
3244 int r = 0;
3245 coll_t cid;
3246 string base = "";
3247 for (int i = 0; i < 100; ++i) base.append("aaaaa");
3248 set<ghobject_t> created;
3249 {
3250 ObjectStore::Transaction t;
3251 t.create_collection(cid, 0);
3252 r = apply_transaction(store, &osr, std::move(t));
3253 ASSERT_EQ(r, 0);
3254 }
3255 for (int i = 0; i < NUM_OBJS; ++i) {
3256 if (!(i % 5)) {
3257 cerr << "Object " << i << std::endl;
3258 }
3259 ObjectStore::Transaction t;
3260 char buf[100];
3261 snprintf(buf, sizeof(buf), "%d", i);
3262 ghobject_t hoid(hobject_t(sobject_t(string(buf) + base, CEPH_NOSNAP)));
3263 t.touch(cid, hoid);
3264 created.insert(hoid);
3265 r = apply_transaction(store, &osr, std::move(t));
3266 ASSERT_EQ(r, 0);
3267 }
3268
3269 for (set<ghobject_t>::iterator i = created.begin();
3270 i != created.end();
3271 ++i) {
3272 struct stat buf;
3273 ASSERT_TRUE(!store->stat(cid, *i, &buf));
3274 }
3275
3276 set<ghobject_t> listed, listed2;
3277 vector<ghobject_t> objects;
3278 r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(), INT_MAX, &objects, 0);
3279 ASSERT_EQ(r, 0);
3280
3281 cerr << "objects.size() is " << objects.size() << std::endl;
3282 for (vector<ghobject_t> ::iterator i = objects.begin();
3283 i != objects.end();
3284 ++i) {
3285 listed.insert(*i);
3286 ASSERT_TRUE(created.count(*i));
3287 }
3288 ASSERT_TRUE(listed.size() == created.size());
3289
3290 ghobject_t start, next;
3291 objects.clear();
3292 r = store->collection_list(
3293 cid,
3294 ghobject_t::get_max(),
3295 ghobject_t::get_max(),
3296 50,
3297 &objects,
3298 &next
3299 );
3300 ASSERT_EQ(r, 0);
3301 ASSERT_TRUE(objects.empty());
3302
3303 objects.clear();
3304 listed.clear();
3305 ghobject_t start2, next2;
3306 while (1) {
3307 r = store->collection_list(cid, start, ghobject_t::get_max(),
3308 50,
3309 &objects,
3310 &next);
3311 ASSERT_TRUE(sorted(objects));
3312 ASSERT_EQ(r, 0);
3313 listed.insert(objects.begin(), objects.end());
3314 if (objects.size() < 50) {
3315 ASSERT_TRUE(next.is_max());
3316 break;
3317 }
3318 objects.clear();
3319
3320 start = next;
3321 }
3322 cerr << "listed.size() is " << listed.size() << std::endl;
3323 ASSERT_TRUE(listed.size() == created.size());
3324 if (listed2.size()) {
3325 ASSERT_EQ(listed.size(), listed2.size());
3326 }
3327 for (set<ghobject_t>::iterator i = listed.begin();
3328 i != listed.end();
3329 ++i) {
3330 ASSERT_TRUE(created.count(*i));
3331 }
3332
3333 for (set<ghobject_t>::iterator i = created.begin();
3334 i != created.end();
3335 ++i) {
3336 ObjectStore::Transaction t;
3337 t.remove(cid, *i);
3338 r = apply_transaction(store, &osr, std::move(t));
3339 ASSERT_EQ(r, 0);
3340 }
3341 cerr << "cleaning up" << std::endl;
3342 {
3343 ObjectStore::Transaction t;
3344 t.remove_collection(cid);
3345 r = apply_transaction(store, &osr, std::move(t));
3346 ASSERT_EQ(r, 0);
3347 }
3348}
3349
3350
3351class ObjectGenerator {
3352public:
3353 virtual ghobject_t create_object(gen_type *gen) = 0;
3354 virtual ~ObjectGenerator() {}
3355};
3356
3357class MixedGenerator : public ObjectGenerator {
3358public:
3359 unsigned seq;
3360 int64_t poolid;
3361 explicit MixedGenerator(int64_t p) : seq(0), poolid(p) {}
3362 ghobject_t create_object(gen_type *gen) override {
3363 char buf[100];
3364 snprintf(buf, sizeof(buf), "OBJ_%u", seq);
3365 string name(buf);
3366 if (seq % 2) {
3367 for (unsigned i = 0; i < 300; ++i) {
3368 name.push_back('a');
3369 }
3370 }
3371 ++seq;
3372 return ghobject_t(
3373 hobject_t(
3374 name, string(), rand() & 2 ? CEPH_NOSNAP : rand(),
3375 (((seq / 1024) % 2) * 0xF00 ) +
3376 (seq & 0xFF),
3377 poolid, ""));
3378 }
3379};
3380
3381class SyntheticWorkloadState {
3382 struct Object {
3383 bufferlist data;
3384 map<string, bufferlist> attrs;
3385 };
3386public:
3387 static const unsigned max_in_flight = 16;
3388 static const unsigned max_objects = 3000;
3389 static const unsigned max_attr_size = 5;
3390 static const unsigned max_attr_name_len = 100;
3391 static const unsigned max_attr_value_len = 1024 * 64;
3392 coll_t cid;
3393 unsigned write_alignment;
3394 unsigned max_object_len, max_write_len;
3395 unsigned in_flight;
3396 map<ghobject_t, Object> contents;
3397 set<ghobject_t> available_objects;
3398 set<ghobject_t> in_flight_objects;
3399 ObjectGenerator *object_gen;
3400 gen_type *rng;
3401 ObjectStore *store;
3402 ObjectStore::Sequencer *osr;
3403
3404 Mutex lock;
3405 Cond cond;
3406
3407 struct EnterExit {
3408 const char *msg;
3409 explicit EnterExit(const char *m) : msg(m) {
3410 //cout << pthread_self() << " enter " << msg << std::endl;
3411 }
3412 ~EnterExit() {
3413 //cout << pthread_self() << " exit " << msg << std::endl;
3414 }
3415 };
3416
3417 class C_SyntheticOnReadable : public Context {
3418 public:
3419 SyntheticWorkloadState *state;
3420 ghobject_t hoid;
3421 C_SyntheticOnReadable(SyntheticWorkloadState *state, ghobject_t hoid)
3422 : state(state), hoid(hoid) {}
3423
3424 void finish(int r) override {
3425 Mutex::Locker locker(state->lock);
3426 EnterExit ee("onreadable finish");
3427 ASSERT_TRUE(state->in_flight_objects.count(hoid));
3428 ASSERT_EQ(r, 0);
3429 state->in_flight_objects.erase(hoid);
3430 if (state->contents.count(hoid))
3431 state->available_objects.insert(hoid);
3432 --(state->in_flight);
3433 state->cond.Signal();
3434
3435 bufferlist r2;
3436 r = state->store->read(state->cid, hoid, 0, state->contents[hoid].data.length(), r2);
3437 assert(bl_eq(state->contents[hoid].data, r2));
3438 state->cond.Signal();
3439 }
3440 };
3441
3442 class C_SyntheticOnStash : public Context {
3443 public:
3444 SyntheticWorkloadState *state;
3445 ghobject_t oid, noid;
3446
3447 C_SyntheticOnStash(SyntheticWorkloadState *state,
3448 ghobject_t oid, ghobject_t noid)
3449 : state(state), oid(oid), noid(noid) {}
3450
3451 void finish(int r) override {
3452 Mutex::Locker locker(state->lock);
3453 EnterExit ee("stash finish");
3454 ASSERT_TRUE(state->in_flight_objects.count(oid));
3455 ASSERT_EQ(r, 0);
3456 state->in_flight_objects.erase(oid);
3457 if (state->contents.count(noid))
3458 state->available_objects.insert(noid);
3459 --(state->in_flight);
3460 bufferlist r2;
3461 r = state->store->read(
3462 state->cid, noid, 0,
3463 state->contents[noid].data.length(), r2);
3464 assert(bl_eq(state->contents[noid].data, r2));
3465 state->cond.Signal();
3466 }
3467 };
3468
3469 class C_SyntheticOnClone : public Context {
3470 public:
3471 SyntheticWorkloadState *state;
3472 ghobject_t oid, noid;
3473
3474 C_SyntheticOnClone(SyntheticWorkloadState *state,
3475 ghobject_t oid, ghobject_t noid)
3476 : state(state), oid(oid), noid(noid) {}
3477
3478 void finish(int r) override {
3479 Mutex::Locker locker(state->lock);
3480 EnterExit ee("clone finish");
3481 ASSERT_TRUE(state->in_flight_objects.count(oid));
3482 ASSERT_EQ(r, 0);
3483 state->in_flight_objects.erase(oid);
3484 if (state->contents.count(oid))
3485 state->available_objects.insert(oid);
3486 if (state->contents.count(noid))
3487 state->available_objects.insert(noid);
3488 --(state->in_flight);
3489 bufferlist r2;
3490 r = state->store->read(state->cid, noid, 0, state->contents[noid].data.length(), r2);
3491 assert(bl_eq(state->contents[noid].data, r2));
3492 state->cond.Signal();
3493 }
3494 };
3495
3496 static void filled_byte_array(bufferlist& bl, size_t size)
3497 {
3498 static const char alphanum[] = "0123456789"
3499 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3500 "abcdefghijklmnopqrstuvwxyz";
3501 if (!size) {
3502 return;
3503 }
3504 bufferptr bp(size);
3505 for (unsigned int i = 0; i < size - 1; i++) {
3506 // severely limit entropy so we can compress...
3507 bp[i] = alphanum[rand() % 10]; //(sizeof(alphanum) - 1)];
3508 }
3509 bp[size - 1] = '\0';
3510
3511 bl.append(bp);
3512 }
3513
3514 SyntheticWorkloadState(ObjectStore *store,
3515 ObjectGenerator *gen,
3516 gen_type *rng,
3517 ObjectStore::Sequencer *osr,
3518 coll_t cid,
3519 unsigned max_size,
3520 unsigned max_write,
3521 unsigned alignment)
3522 : cid(cid), write_alignment(alignment), max_object_len(max_size),
3523 max_write_len(max_write), in_flight(0), object_gen(gen),
3524 rng(rng), store(store), osr(osr), lock("State lock") {}
3525
3526 int init() {
3527 ObjectStore::Transaction t;
3528 t.create_collection(cid, 0);
3529 return apply_transaction(store, osr, std::move(t));
3530 }
3531 void shutdown() {
3532 while (1) {
3533 vector<ghobject_t> objects;
3534 int r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
3535 10, &objects, 0);
3536 assert(r >= 0);
3537 if (objects.empty())
3538 break;
3539 ObjectStore::Transaction t;
3540 for (vector<ghobject_t>::iterator p = objects.begin();
3541 p != objects.end(); ++p) {
3542 t.remove(cid, *p);
3543 }
3544 apply_transaction(store, osr, std::move(t));
3545 }
3546 ObjectStore::Transaction t;
3547 t.remove_collection(cid);
3548 apply_transaction(store, osr, std::move(t));
3549 }
3550 void statfs(store_statfs_t& stat) {
3551 store->statfs(&stat);
3552 }
3553
3554 ghobject_t get_uniform_random_object() {
3555 while (in_flight >= max_in_flight || available_objects.empty())
3556 cond.Wait(lock);
3557 boost::uniform_int<> choose(0, available_objects.size() - 1);
3558 int index = choose(*rng);
3559 set<ghobject_t>::iterator i = available_objects.begin();
3560 for ( ; index > 0; --index, ++i) ;
3561 ghobject_t ret = *i;
3562 return ret;
3563 }
3564
3565 void wait_for_ready() {
3566 while (in_flight >= max_in_flight)
3567 cond.Wait(lock);
3568 }
3569
3570 void wait_for_done() {
3571 osr->flush();
3572 Mutex::Locker locker(lock);
3573 while (in_flight)
3574 cond.Wait(lock);
3575 }
3576
3577 bool can_create() {
3578 return (available_objects.size() + in_flight_objects.size()) < max_objects;
3579 }
3580
3581 bool can_unlink() {
3582 return (available_objects.size() + in_flight_objects.size()) > 0;
3583 }
3584
3585 unsigned get_random_alloc_hints() {
3586 unsigned f = 0;
3587 {
3588 boost::uniform_int<> u(0, 3);
3589 switch (u(*rng)) {
3590 case 1:
3591 f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE;
3592 break;
3593 case 2:
3594 f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE;
3595 break;
3596 }
3597 }
3598 {
3599 boost::uniform_int<> u(0, 3);
3600 switch (u(*rng)) {
3601 case 1:
3602 f |= CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ;
3603 break;
3604 case 2:
3605 f |= CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ;
3606 break;
3607 }
3608 }
3609 {
3610 // append_only, immutable
3611 boost::uniform_int<> u(0, 4);
3612 f |= u(*rng) << 4;
3613 }
3614 {
3615 boost::uniform_int<> u(0, 3);
3616 switch (u(*rng)) {
3617 case 1:
3618 f |= CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED;
3619 break;
3620 case 2:
3621 f |= CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED;
3622 break;
3623 }
3624 }
3625 {
3626 boost::uniform_int<> u(0, 3);
3627 switch (u(*rng)) {
3628 case 1:
3629 f |= CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE;
3630 break;
3631 case 2:
3632 f |= CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE;
3633 break;
3634 }
3635 }
3636 return f;
3637 }
3638
3639 int touch() {
3640 Mutex::Locker locker(lock);
3641 EnterExit ee("touch");
3642 if (!can_create())
3643 return -ENOSPC;
3644 wait_for_ready();
3645 ghobject_t new_obj = object_gen->create_object(rng);
3646 available_objects.erase(new_obj);
3647 ObjectStore::Transaction t;
3648 t.touch(cid, new_obj);
3649 boost::uniform_int<> u(17, 22);
3650 boost::uniform_int<> v(12, 17);
3651 t.set_alloc_hint(cid, new_obj,
3652 1ull << u(*rng),
3653 1ull << v(*rng),
3654 get_random_alloc_hints());
3655 ++in_flight;
3656 in_flight_objects.insert(new_obj);
3657 if (!contents.count(new_obj))
3658 contents[new_obj] = Object();
3659 int status = store->queue_transaction(osr, std::move(t), new C_SyntheticOnReadable(this, new_obj));
3660 return status;
3661 }
3662
3663 int stash() {
3664 Mutex::Locker locker(lock);
3665 EnterExit ee("stash");
3666 if (!can_unlink())
3667 return -ENOENT;
3668 if (!can_create())
3669 return -ENOSPC;
3670 wait_for_ready();
3671
3672 ghobject_t old_obj;
3673 int max = 20;
3674 do {
3675 old_obj = get_uniform_random_object();
3676 } while (--max && !contents[old_obj].data.length());
3677 available_objects.erase(old_obj);
3678 ghobject_t new_obj = old_obj;
3679 new_obj.generation++;
3680 available_objects.erase(new_obj);
3681
3682 ObjectStore::Transaction t;
3683 t.collection_move_rename(cid, old_obj, cid, new_obj);
3684 ++in_flight;
3685 in_flight_objects.insert(old_obj);
3686
3687 contents[new_obj].attrs = contents[old_obj].attrs;
3688 contents[new_obj].data = contents[old_obj].data;
3689 contents.erase(old_obj);
3690 int status = store->queue_transaction(
3691 osr, std::move(t),
3692 new C_SyntheticOnStash(this, old_obj, new_obj));
3693 return status;
3694 }
3695
3696 int clone() {
3697 Mutex::Locker locker(lock);
3698 EnterExit ee("clone");
3699 if (!can_unlink())
3700 return -ENOENT;
3701 if (!can_create())
3702 return -ENOSPC;
3703 wait_for_ready();
3704
3705 ghobject_t old_obj;
3706 int max = 20;
3707 do {
3708 old_obj = get_uniform_random_object();
3709 } while (--max && !contents[old_obj].data.length());
3710 available_objects.erase(old_obj);
3711 ghobject_t new_obj = object_gen->create_object(rng);
3712 // make the hash match
3713 new_obj.hobj.set_hash(old_obj.hobj.get_hash());
3714 available_objects.erase(new_obj);
3715
3716 ObjectStore::Transaction t;
3717 t.clone(cid, old_obj, new_obj);
3718 ++in_flight;
3719 in_flight_objects.insert(old_obj);
3720
3721 contents[new_obj].attrs = contents[old_obj].attrs;
3722 contents[new_obj].data = contents[old_obj].data;
3723
3724 int status = store->queue_transaction(
3725 osr, std::move(t),
3726 new C_SyntheticOnClone(this, old_obj, new_obj));
3727 return status;
3728 }
3729
3730 int clone_range() {
3731 Mutex::Locker locker(lock);
3732 EnterExit ee("clone_range");
3733 if (!can_unlink())
3734 return -ENOENT;
3735 if (!can_create())
3736 return -ENOSPC;
3737 wait_for_ready();
3738
3739 ghobject_t old_obj;
3740 int max = 20;
3741 do {
3742 old_obj = get_uniform_random_object();
3743 } while (--max && !contents[old_obj].data.length());
3744 bufferlist &srcdata = contents[old_obj].data;
3745 if (srcdata.length() == 0) {
3746 return 0;
3747 }
3748 available_objects.erase(old_obj);
3749 ghobject_t new_obj = get_uniform_random_object();
3750 available_objects.erase(new_obj);
3751
3752 boost::uniform_int<> u1(0, max_object_len - max_write_len);
3753 boost::uniform_int<> u2(0, max_write_len);
3754 uint64_t srcoff = u1(*rng);
3755 // make src and dst offsets match, since that's what the osd does
3756 uint64_t dstoff = srcoff; //u1(*rng);
3757 uint64_t len = u2(*rng);
3758 if (write_alignment) {
3759 srcoff = ROUND_UP_TO(srcoff, write_alignment);
3760 dstoff = ROUND_UP_TO(dstoff, write_alignment);
3761 len = ROUND_UP_TO(len, write_alignment);
3762 }
3763
3764 if (srcoff > srcdata.length() - 1) {
3765 srcoff = srcdata.length() - 1;
3766 }
3767 if (srcoff + len > srcdata.length()) {
3768 len = srcdata.length() - srcoff;
3769 }
3770 if (0)
3771 cout << __func__ << " from " << srcoff << "~" << len
3772 << " (size " << srcdata.length() << ") to "
3773 << dstoff << "~" << len << std::endl;
3774
3775 ObjectStore::Transaction t;
3776 t.clone_range(cid, old_obj, new_obj, srcoff, len, dstoff);
3777 ++in_flight;
3778 in_flight_objects.insert(old_obj);
3779
3780 bufferlist bl;
3781 if (srcoff < srcdata.length()) {
3782 if (srcoff + len > srcdata.length()) {
3783 bl.substr_of(srcdata, srcoff, srcdata.length() - srcoff);
3784 } else {
3785 bl.substr_of(srcdata, srcoff, len);
3786 }
3787 }
3788
3789 bufferlist& dstdata = contents[new_obj].data;
3790 if (dstdata.length() <= dstoff) {
3791 if (bl.length() > 0) {
3792 dstdata.append_zero(dstoff - dstdata.length());
3793 dstdata.append(bl);
3794 }
3795 } else {
3796 bufferlist value;
3797 assert(dstdata.length() > dstoff);
3798 dstdata.copy(0, dstoff, value);
3799 value.append(bl);
3800 if (value.length() < dstdata.length())
3801 dstdata.copy(value.length(),
3802 dstdata.length() - value.length(), value);
3803 value.swap(dstdata);
3804 }
3805
3806 int status = store->queue_transaction(
3807 osr, std::move(t), new C_SyntheticOnClone(this, old_obj, new_obj));
3808 return status;
3809 }
3810
3811
3812 int write() {
3813 Mutex::Locker locker(lock);
3814 EnterExit ee("write");
3815 if (!can_unlink())
3816 return -ENOENT;
3817 wait_for_ready();
3818
3819 ghobject_t new_obj = get_uniform_random_object();
3820 available_objects.erase(new_obj);
3821 ObjectStore::Transaction t;
3822
3823 boost::uniform_int<> u1(0, max_object_len - max_write_len);
3824 boost::uniform_int<> u2(0, max_write_len);
3825 uint64_t offset = u1(*rng);
3826 uint64_t len = u2(*rng);
3827 bufferlist bl;
3828 if (write_alignment) {
3829 offset = ROUND_UP_TO(offset, write_alignment);
3830 len = ROUND_UP_TO(len, write_alignment);
3831 }
3832
3833 filled_byte_array(bl, len);
3834
3835 bufferlist& data = contents[new_obj].data;
3836 if (data.length() <= offset) {
3837 if (len > 0) {
3838 data.append_zero(offset-data.length());
3839 data.append(bl);
3840 }
3841 } else {
3842 bufferlist value;
3843 assert(data.length() > offset);
3844 data.copy(0, offset, value);
3845 value.append(bl);
3846 if (value.length() < data.length())
3847 data.copy(value.length(),
3848 data.length()-value.length(), value);
3849 value.swap(data);
3850 }
3851
3852 t.write(cid, new_obj, offset, len, bl);
3853 ++in_flight;
3854 in_flight_objects.insert(new_obj);
3855 int status = store->queue_transaction(
3856 osr, std::move(t), new C_SyntheticOnReadable(this, new_obj));
3857 return status;
3858 }
3859
3860 int truncate() {
3861 Mutex::Locker locker(lock);
3862 EnterExit ee("truncate");
3863 if (!can_unlink())
3864 return -ENOENT;
3865 wait_for_ready();
3866
3867 ghobject_t obj = get_uniform_random_object();
3868 available_objects.erase(obj);
3869 ObjectStore::Transaction t;
3870
3871 boost::uniform_int<> choose(0, max_object_len);
3872 size_t len = choose(*rng);
3873 if (write_alignment) {
3874 len = ROUND_UP_TO(len, write_alignment);
3875 }
3876
3877 t.truncate(cid, obj, len);
3878 ++in_flight;
3879 in_flight_objects.insert(obj);
3880 bufferlist& data = contents[obj].data;
3881 if (data.length() <= len) {
3882 data.append_zero(len - data.length());
3883 } else {
3884 bufferlist bl;
3885 data.copy(0, len, bl);
3886 bl.swap(data);
3887 }
3888
3889 int status = store->queue_transaction(
3890 osr, std::move(t), new C_SyntheticOnReadable(this, obj));
3891 return status;
3892 }
3893
3894 int zero() {
3895 Mutex::Locker locker(lock);
3896 EnterExit ee("zero");
3897 if (!can_unlink())
3898 return -ENOENT;
3899 wait_for_ready();
3900
3901 ghobject_t new_obj = get_uniform_random_object();
3902 available_objects.erase(new_obj);
3903 ObjectStore::Transaction t;
3904
3905 boost::uniform_int<> u1(0, max_object_len - max_write_len);
3906 boost::uniform_int<> u2(0, max_write_len);
3907 uint64_t offset = u1(*rng);
3908 uint64_t len = u2(*rng);
3909 if (write_alignment) {
3910 offset = ROUND_UP_TO(offset, write_alignment);
3911 len = ROUND_UP_TO(len, write_alignment);
3912 }
3913
b32b8144
FG
3914 if (len > 0) {
3915 auto& data = contents[new_obj].data;
3916 if (data.length() < offset + len) {
3917 data.append_zero(offset+len-data.length());
3918 }
3919 bufferlist n;
3920 n.substr_of(data, 0, offset);
3921 n.append_zero(len);
3922 if (data.length() > offset + len)
3923 data.copy(offset + len, data.length() - offset - len, n);
3924 data.swap(n);
7c673cae 3925 }
7c673cae
FG
3926
3927 t.zero(cid, new_obj, offset, len);
3928 ++in_flight;
3929 in_flight_objects.insert(new_obj);
3930 int status = store->queue_transaction(
3931 osr, std::move(t), new C_SyntheticOnReadable(this, new_obj));
3932 return status;
3933 }
3934
3935 void read() {
3936 EnterExit ee("read");
3937 boost::uniform_int<> u1(0, max_object_len/2);
3938 boost::uniform_int<> u2(0, max_object_len);
3939 uint64_t offset = u1(*rng);
3940 uint64_t len = u2(*rng);
3941 if (offset > len)
3942 swap(offset, len);
3943
3944 ghobject_t obj;
3945 bufferlist expected;
3946 int r;
3947 {
3948 Mutex::Locker locker(lock);
3949 EnterExit ee("read locked");
3950 if (!can_unlink())
3951 return ;
3952 wait_for_ready();
3953
3954 obj = get_uniform_random_object();
3955 expected = contents[obj].data;
3956 }
3957 bufferlist bl, result;
3958 if (0) cout << " obj " << obj
3959 << " size " << expected.length()
3960 << " offset " << offset
3961 << " len " << len << std::endl;
3962 r = store->read(cid, obj, offset, len, result);
3963 if (offset >= expected.length()) {
3964 ASSERT_EQ(r, 0);
3965 } else {
3966 size_t max_len = expected.length() - offset;
3967 if (len > max_len)
3968 len = max_len;
3969 assert(len == result.length());
3970 ASSERT_EQ(len, result.length());
3971 expected.copy(offset, len, bl);
3972 ASSERT_EQ(r, (int)len);
3973 ASSERT_TRUE(bl_eq(bl, result));
3974 }
3975 }
3976
3977 int setattrs() {
3978 Mutex::Locker locker(lock);
3979 EnterExit ee("setattrs");
3980 if (!can_unlink())
3981 return -ENOENT;
3982 wait_for_ready();
3983
3984 ghobject_t obj = get_uniform_random_object();
3985 available_objects.erase(obj);
3986 ObjectStore::Transaction t;
3987
3988 boost::uniform_int<> u0(1, max_attr_size);
3989 boost::uniform_int<> u1(4, max_attr_name_len);
3990 boost::uniform_int<> u2(4, max_attr_value_len);
3991 boost::uniform_int<> u3(0, 100);
3992 uint64_t size = u0(*rng);
3993 uint64_t name_len;
3994 map<string, bufferlist> attrs;
3995 set<string> keys;
3996 for (map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
3997 it != contents[obj].attrs.end(); ++it)
3998 keys.insert(it->first);
3999
4000 while (size--) {
4001 bufferlist name, value;
4002 uint64_t get_exist = u3(*rng);
4003 uint64_t value_len = u2(*rng);
4004 filled_byte_array(value, value_len);
4005 if (get_exist < 50 && keys.size()) {
4006 set<string>::iterator k = keys.begin();
4007 attrs[*k] = value;
4008 contents[obj].attrs[*k] = value;
4009 keys.erase(k);
4010 } else {
4011 name_len = u1(*rng);
4012 filled_byte_array(name, name_len);
4013 attrs[name.c_str()] = value;
4014 contents[obj].attrs[name.c_str()] = value;
4015 }
4016 }
4017 t.setattrs(cid, obj, attrs);
4018 ++in_flight;
4019 in_flight_objects.insert(obj);
4020 int status = store->queue_transaction(
4021 osr, std::move(t), new C_SyntheticOnReadable(this, obj));
4022 return status;
4023 }
4024
4025 void getattrs() {
4026 EnterExit ee("getattrs");
4027 ghobject_t obj;
4028 map<string, bufferlist> expected;
4029 {
4030 Mutex::Locker locker(lock);
4031 EnterExit ee("getattrs locked");
4032 if (!can_unlink())
4033 return ;
4034 wait_for_ready();
4035
4036 int retry = 10;
4037 do {
4038 obj = get_uniform_random_object();
4039 if (!--retry)
4040 return ;
4041 } while (contents[obj].attrs.empty());
4042 expected = contents[obj].attrs;
4043 }
4044 map<string, bufferlist> attrs;
4045 int r = store->getattrs(cid, obj, attrs);
4046 ASSERT_TRUE(r == 0);
4047 ASSERT_TRUE(attrs.size() == expected.size());
4048 for (map<string, bufferlist>::iterator it = expected.begin();
4049 it != expected.end(); ++it) {
4050 ASSERT_TRUE(bl_eq(attrs[it->first], it->second));
4051 }
4052 }
4053
4054 void getattr() {
4055 EnterExit ee("getattr");
4056 ghobject_t obj;
4057 int r;
4058 int retry;
4059 map<string, bufferlist> expected;
4060 {
4061 Mutex::Locker locker(lock);
4062 EnterExit ee("getattr locked");
4063 if (!can_unlink())
4064 return ;
4065 wait_for_ready();
4066
4067 retry = 10;
4068 do {
4069 obj = get_uniform_random_object();
4070 if (!--retry)
4071 return ;
4072 } while (contents[obj].attrs.empty());
4073 expected = contents[obj].attrs;
4074 }
4075 boost::uniform_int<> u(0, expected.size()-1);
4076 retry = u(*rng);
4077 map<string, bufferlist>::iterator it = expected.begin();
4078 while (retry) {
4079 retry--;
4080 ++it;
4081 }
4082
4083 bufferlist bl;
4084 r = store->getattr(cid, obj, it->first, bl);
4085 ASSERT_EQ(r, 0);
4086 ASSERT_TRUE(bl_eq(it->second, bl));
4087 }
4088
4089 int rmattr() {
4090 Mutex::Locker locker(lock);
4091 EnterExit ee("rmattr");
4092 if (!can_unlink())
4093 return -ENOENT;
4094 wait_for_ready();
4095
4096 ghobject_t obj;
4097 int retry = 10;
4098 do {
4099 obj = get_uniform_random_object();
4100 if (!--retry)
4101 return 0;
4102 } while (contents[obj].attrs.empty());
4103
4104 boost::uniform_int<> u(0, contents[obj].attrs.size()-1);
4105 retry = u(*rng);
4106 map<string, bufferlist>::iterator it = contents[obj].attrs.begin();
4107 while (retry) {
4108 retry--;
4109 ++it;
4110 }
4111
4112 available_objects.erase(obj);
4113 ObjectStore::Transaction t;
4114 t.rmattr(cid, obj, it->first);
4115
4116 contents[obj].attrs.erase(it->first);
4117 ++in_flight;
4118 in_flight_objects.insert(obj);
4119 int status = store->queue_transaction(
4120 osr, std::move(t), new C_SyntheticOnReadable(this, obj));
4121 return status;
4122 }
4123
4124 void fsck(bool deep) {
4125 Mutex::Locker locker(lock);
4126 EnterExit ee("fsck");
4127 while (in_flight)
4128 cond.Wait(lock);
4129 store->umount();
4130 int r = store->fsck(deep);
4131 assert(r == 0 || r == -EOPNOTSUPP);
4132 store->mount();
4133 }
4134
4135 void scan() {
4136 Mutex::Locker locker(lock);
4137 EnterExit ee("scan");
4138 while (in_flight)
4139 cond.Wait(lock);
4140 vector<ghobject_t> objects;
4141 set<ghobject_t> objects_set, objects_set2;
4142 ghobject_t next, current;
4143 while (1) {
4144 //cerr << "scanning..." << std::endl;
4145 int r = store->collection_list(cid, current, ghobject_t::get_max(), 100,
4146 &objects, &next);
4147 ASSERT_EQ(r, 0);
4148 ASSERT_TRUE(sorted(objects));
4149 objects_set.insert(objects.begin(), objects.end());
4150 objects.clear();
4151 if (next.is_max()) break;
4152 current = next;
4153 }
4154 if (objects_set.size() != available_objects.size()) {
4155 for (set<ghobject_t>::iterator p = objects_set.begin();
4156 p != objects_set.end();
4157 ++p)
4158 if (available_objects.count(*p) == 0) {
4159 cerr << "+ " << *p << std::endl;
4160 ceph_abort();
4161 }
4162 for (set<ghobject_t>::iterator p = available_objects.begin();
4163 p != available_objects.end();
4164 ++p)
4165 if (objects_set.count(*p) == 0)
4166 cerr << "- " << *p << std::endl;
4167 //cerr << " objects_set: " << objects_set << std::endl;
4168 //cerr << " available_set: " << available_objects << std::endl;
4169 assert(0 == "badness");
4170 }
4171
4172 ASSERT_EQ(objects_set.size(), available_objects.size());
4173 for (set<ghobject_t>::iterator i = objects_set.begin();
4174 i != objects_set.end();
4175 ++i) {
4176 ASSERT_GT(available_objects.count(*i), (unsigned)0);
4177 }
4178
4179 int r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
4180 INT_MAX, &objects, 0);
4181 ASSERT_EQ(r, 0);
4182 objects_set2.insert(objects.begin(), objects.end());
4183 ASSERT_EQ(objects_set2.size(), available_objects.size());
4184 for (set<ghobject_t>::iterator i = objects_set2.begin();
4185 i != objects_set2.end();
4186 ++i) {
4187 ASSERT_GT(available_objects.count(*i), (unsigned)0);
4188 if (available_objects.count(*i) == 0) {
4189 cerr << "+ " << *i << std::endl;
4190 }
4191 }
4192 }
4193
4194 void stat() {
4195 EnterExit ee("stat");
4196 ghobject_t hoid;
4197 uint64_t expected;
4198 {
4199 Mutex::Locker locker(lock);
4200 EnterExit ee("stat lock1");
4201 if (!can_unlink())
4202 return ;
4203 hoid = get_uniform_random_object();
4204 in_flight_objects.insert(hoid);
4205 available_objects.erase(hoid);
4206 ++in_flight;
4207 expected = contents[hoid].data.length();
4208 }
4209 struct stat buf;
4210 int r = store->stat(cid, hoid, &buf);
4211 ASSERT_EQ(0, r);
4212 assert((uint64_t)buf.st_size == expected);
4213 ASSERT_TRUE((uint64_t)buf.st_size == expected);
4214 {
4215 Mutex::Locker locker(lock);
4216 EnterExit ee("stat lock2");
4217 --in_flight;
4218 cond.Signal();
4219 in_flight_objects.erase(hoid);
4220 available_objects.insert(hoid);
4221 }
4222 }
4223
4224 int unlink() {
4225 Mutex::Locker locker(lock);
4226 EnterExit ee("unlink");
4227 if (!can_unlink())
4228 return -ENOENT;
4229 ghobject_t to_remove = get_uniform_random_object();
4230 ObjectStore::Transaction t;
4231 t.remove(cid, to_remove);
4232 ++in_flight;
4233 available_objects.erase(to_remove);
4234 in_flight_objects.insert(to_remove);
4235 contents.erase(to_remove);
4236 int status = store->queue_transaction(osr, std::move(t), new C_SyntheticOnReadable(this, to_remove));
4237 return status;
4238 }
4239
4240 void print_internal_state() {
4241 Mutex::Locker locker(lock);
4242 cerr << "available_objects: " << available_objects.size()
4243 << " in_flight_objects: " << in_flight_objects.size()
4244 << " total objects: " << in_flight_objects.size() + available_objects.size()
4245 << " in_flight " << in_flight << std::endl;
4246 }
4247};
4248
4249
4250void doSyntheticTest(boost::scoped_ptr<ObjectStore>& store,
4251 int num_ops,
4252 uint64_t max_obj, uint64_t max_wr, uint64_t align)
4253{
4254 ObjectStore::Sequencer osr("test");
4255 MixedGenerator gen(555);
4256 gen_type rng(time(NULL));
4257 coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
4258
4259 g_ceph_context->_conf->set_val("bluestore_fsck_on_mount", "false");
4260 g_ceph_context->_conf->set_val("bluestore_fsck_on_umount", "false");
4261 g_ceph_context->_conf->apply_changes(NULL);
4262
4263 SyntheticWorkloadState test_obj(store.get(), &gen, &rng, &osr, cid,
4264 max_obj, max_wr, align);
4265 test_obj.init();
4266 for (int i = 0; i < num_ops/10; ++i) {
4267 if (!(i % 500)) cerr << "seeding object " << i << std::endl;
4268 test_obj.touch();
4269 }
4270 for (int i = 0; i < num_ops; ++i) {
4271 if (!(i % 1000)) {
4272 cerr << "Op " << i << std::endl;
4273 test_obj.print_internal_state();
4274 }
4275 boost::uniform_int<> true_false(0, 999);
4276 int val = true_false(rng);
4277 if (val > 998) {
4278 test_obj.fsck(true);
4279 } else if (val > 997) {
4280 test_obj.fsck(false);
4281 } else if (val > 970) {
4282 test_obj.scan();
4283 } else if (val > 950) {
4284 test_obj.stat();
4285 } else if (val > 850) {
4286 test_obj.zero();
4287 } else if (val > 800) {
4288 test_obj.unlink();
4289 } else if (val > 550) {
4290 test_obj.write();
4291 } else if (val > 500) {
4292 test_obj.clone();
4293 } else if (val > 450) {
4294 test_obj.clone_range();
4295 } else if (val > 300) {
4296 test_obj.stash();
4297 } else if (val > 100) {
4298 test_obj.read();
4299 } else {
4300 test_obj.truncate();
4301 }
4302 }
4303 test_obj.wait_for_done();
4304 test_obj.shutdown();
4305
4306 g_ceph_context->_conf->set_val("bluestore_fsck_on_mount", "true");
4307 g_ceph_context->_conf->set_val("bluestore_fsck_on_umount", "true");
4308 g_ceph_context->_conf->apply_changes(NULL);
4309}
4310
4311TEST_P(StoreTest, Synthetic) {
4312 doSyntheticTest(store, 10000, 400*1024, 40*1024, 0);
4313}
4314
4315
4316TEST_P(StoreTestSpecificAUSize, SyntheticMatrixSharding) {
4317 if (string(GetParam()) != "bluestore")
4318 return;
4319
4320 const char *m[][10] = {
4321 { "bluestore_min_alloc_size", "4096", 0 }, // must be the first!
4322 { "num_ops", "50000", 0 },
4323 { "max_write", "65536", 0 },
4324 { "max_size", "262144", 0 },
4325 { "alignment", "4096", 0 },
4326 { "bluestore_max_blob_size", "65536", 0 },
4327 { "bluestore_extent_map_shard_min_size", "60", 0 },
4328 { "bluestore_extent_map_shard_max_size", "300", 0 },
4329 { "bluestore_extent_map_shard_target_size", "150", 0 },
4330 { "bluestore_default_buffered_read", "true", 0 },
4331 { "bluestore_default_buffered_write", "true", 0 },
4332 { 0 },
4333 };
4334 do_matrix(m, store, doSyntheticTest);
4335}
4336
4337TEST_P(StoreTestSpecificAUSize, ZipperPatternSharded) {
4338 if(string(GetParam()) != "bluestore")
4339 return;
4340 StartDeferred(4096);
4341
4342 int r;
4343 ObjectStore::Sequencer osr("test");
4344 coll_t cid;
4345 ghobject_t a(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
4346 {
4347 ObjectStore::Transaction t;
4348 t.create_collection(cid, 0);
4349 cerr << "Creating collection " << cid << std::endl;
4350 r = apply_transaction(store, &osr, std::move(t));
4351 ASSERT_EQ(r, 0);
4352 }
4353 bufferlist bl;
4354 int len = 4096;
4355 bufferptr bp(len);
4356 bp.zero();
4357 bl.append(bp);
4358 for (int i=0; i<1000; ++i) {
4359 ObjectStore::Transaction t;
4360 t.write(cid, a, i*2*len, len, bl, 0);
4361 r = apply_transaction(store, &osr, std::move(t));
4362 ASSERT_EQ(r, 0);
4363 }
4364 for (int i=0; i<1000; ++i) {
4365 ObjectStore::Transaction t;
4366 t.write(cid, a, i*2*len + 1, len, bl, 0);
4367 r = apply_transaction(store, &osr, std::move(t));
4368 ASSERT_EQ(r, 0);
4369 }
4370 {
4371 ObjectStore::Transaction t;
4372 t.remove(cid, a);
4373 t.remove_collection(cid);
4374 cerr << "Cleaning" << std::endl;
4375 r = apply_transaction(store, &osr, std::move(t));
4376 ASSERT_EQ(r, 0);
4377 }
4378}
4379
4380TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumAlgorithm) {
4381 if (string(GetParam()) != "bluestore")
4382 return;
4383
4384 const char *m[][10] = {
4385 { "bluestore_min_alloc_size", "65536", 0 }, // must be the first!
4386 { "max_write", "65536", 0 },
4387 { "max_size", "1048576", 0 },
4388 { "alignment", "16", 0 },
4389 { "bluestore_csum_type", "crc32c", "crc32c_16", "crc32c_8", "xxhash32",
4390 "xxhash64", "none", 0 },
4391 { "bluestore_default_buffered_write", "false", 0 },
4392 { 0 },
4393 };
4394 do_matrix(m, store, doSyntheticTest);
4395}
4396
4397TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCsumVsCompression) {
4398 if (string(GetParam()) != "bluestore")
4399 return;
4400
4401 const char *m[][10] = {
4402 { "bluestore_min_alloc_size", "4096", "16384", 0 }, //to be the first!
4403 { "max_write", "131072", 0 },
4404 { "max_size", "262144", 0 },
4405 { "alignment", "512", 0 },
4406 { "bluestore_compression_mode", "force", 0},
4407 { "bluestore_compression_algorithm", "snappy", "zlib", 0 },
4408 { "bluestore_csum_type", "crc32c", 0 },
4409 { "bluestore_default_buffered_read", "true", "false", 0 },
4410 { "bluestore_default_buffered_write", "true", "false", 0 },
4411 { "bluestore_sync_submit_transaction", "false", 0 },
4412 { 0 },
4413 };
4414 do_matrix(m, store, doSyntheticTest);
4415}
4416
4417TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompression) {
4418 if (string(GetParam()) != "bluestore")
4419 return;
4420
4421 const char *m[][10] = {
4422 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4423 { "max_write", "1048576", 0 },
4424 { "max_size", "4194304", 0 },
4425 { "alignment", "65536", 0 },
4426 { "bluestore_compression_mode", "force", "aggressive", "passive", "none", 0},
4427 { "bluestore_default_buffered_write", "false", 0 },
4428 { "bluestore_sync_submit_transaction", "true", 0 },
4429 { 0 },
4430 };
4431 do_matrix(m, store, doSyntheticTest);
4432}
4433
4434TEST_P(StoreTestSpecificAUSize, SyntheticMatrixCompressionAlgorithm) {
4435 if (string(GetParam()) != "bluestore")
4436 return;
4437
4438 const char *m[][10] = {
4439 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4440 { "max_write", "1048576", 0 },
4441 { "max_size", "4194304", 0 },
4442 { "alignment", "65536", 0 },
4443 { "bluestore_compression_algorithm", "zlib", "snappy", 0 },
4444 { "bluestore_compression_mode", "force", 0 },
4445 { "bluestore_default_buffered_write", "false", 0 },
4446 { 0 },
4447 };
4448 do_matrix(m, store, doSyntheticTest);
4449}
4450
4451TEST_P(StoreTestSpecificAUSize, SyntheticMatrixNoCsum) {
4452 if (string(GetParam()) != "bluestore")
4453 return;
4454
4455 const char *m[][10] = {
4456 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4457 { "max_write", "65536", 0 },
4458 { "max_size", "1048576", 0 },
4459 { "alignment", "512", 0 },
4460 { "bluestore_max_blob_size", "262144", 0 },
4461 { "bluestore_compression_mode", "force", "none", 0},
4462 { "bluestore_csum_type", "none", 0},
4463 { "bluestore_default_buffered_read", "true", "false", 0 },
4464 { "bluestore_default_buffered_write", "true", 0 },
4465 { "bluestore_sync_submit_transaction", "true", "false", 0 },
4466 { 0 },
4467 };
4468 do_matrix(m, store, doSyntheticTest);
4469}
4470
4471TEST_P(StoreTestSpecificAUSize, SyntheticMatrixPreferDeferred) {
4472 if (string(GetParam()) != "bluestore")
4473 return;
4474
4475 const char *m[][10] = {
4476 { "bluestore_min_alloc_size", "4096", "65536", 0 }, // to be the first!
4477 { "max_write", "65536", 0 },
4478 { "max_size", "1048576", 0 },
4479 { "alignment", "512", 0 },
4480 { "bluestore_max_blob_size", "262144", 0 },
4481 { "bluestore_compression_mode", "force", "none", 0},
4482 { "bluestore_prefer_deferred_size", "32768", "0", 0},
4483 { 0 },
4484 };
4485 do_matrix(m, store, doSyntheticTest);
4486}
4487
4488TEST_P(StoreTest, AttrSynthetic) {
4489 ObjectStore::Sequencer osr("test");
4490 MixedGenerator gen(447);
4491 gen_type rng(time(NULL));
4492 coll_t cid(spg_t(pg_t(0,447),shard_id_t::NO_SHARD));
4493
4494 SyntheticWorkloadState test_obj(store.get(), &gen, &rng, &osr, cid, 40*1024, 4*1024, 0);
4495 test_obj.init();
4496 for (int i = 0; i < 500; ++i) {
4497 if (!(i % 10)) cerr << "seeding object " << i << std::endl;
4498 test_obj.touch();
4499 }
4500 for (int i = 0; i < 1000; ++i) {
4501 if (!(i % 100)) {
4502 cerr << "Op " << i << std::endl;
4503 test_obj.print_internal_state();
4504 }
4505 boost::uniform_int<> true_false(0, 99);
4506 int val = true_false(rng);
4507 if (val > 97) {
4508 test_obj.scan();
4509 } else if (val > 93) {
4510 test_obj.stat();
4511 } else if (val > 75) {
4512 test_obj.rmattr();
4513 } else if (val > 47) {
4514 test_obj.setattrs();
4515 } else if (val > 45) {
4516 test_obj.clone();
4517 } else if (val > 37) {
4518 test_obj.stash();
4519 } else if (val > 30) {
4520 test_obj.getattrs();
4521 } else {
4522 test_obj.getattr();
4523 }
4524 }
4525 test_obj.wait_for_done();
4526 test_obj.shutdown();
4527}
4528
4529TEST_P(StoreTest, HashCollisionTest) {
4530 ObjectStore::Sequencer osr("test");
4531 int64_t poolid = 11;
4532 coll_t cid(spg_t(pg_t(0,poolid),shard_id_t::NO_SHARD));
4533 int r;
4534 {
4535 ObjectStore::Transaction t;
4536 t.create_collection(cid, 0);
4537 r = apply_transaction(store, &osr, std::move(t));
4538 ASSERT_EQ(r, 0);
4539 }
4540 string base = "";
4541 for (int i = 0; i < 100; ++i) base.append("aaaaa");
4542 set<ghobject_t> created;
4543 for (int n = 0; n < 10; ++n) {
4544 char nbuf[100];
4545 sprintf(nbuf, "n%d", n);
4546 for (int i = 0; i < 1000; ++i) {
4547 char buf[100];
4548 sprintf(buf, "%d", i);
4549 if (!(i % 100)) {
4550 cerr << "Object n" << n << " "<< i << std::endl;
4551 }
4552 ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, 0, poolid, string(nbuf)));
4553 {
4554 ObjectStore::Transaction t;
4555 t.touch(cid, hoid);
4556 r = apply_transaction(store, &osr, std::move(t));
4557 ASSERT_EQ(r, 0);
4558 }
4559 created.insert(hoid);
4560 }
4561 }
4562 vector<ghobject_t> objects;
4563 r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(), INT_MAX, &objects, 0);
4564 ASSERT_EQ(r, 0);
4565 set<ghobject_t> listed(objects.begin(), objects.end());
4566 cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
4567 ASSERT_TRUE(listed.size() == created.size());
4568 objects.clear();
4569 listed.clear();
4570 ghobject_t current, next;
4571 while (1) {
4572 r = store->collection_list(cid, current, ghobject_t::get_max(), 60,
4573 &objects, &next);
4574 ASSERT_EQ(r, 0);
4575 ASSERT_TRUE(sorted(objects));
4576 for (vector<ghobject_t>::iterator i = objects.begin();
4577 i != objects.end();
4578 ++i) {
4579 if (listed.count(*i))
4580 cerr << *i << " repeated" << std::endl;
4581 listed.insert(*i);
4582 }
4583 if (objects.size() < 50) {
4584 ASSERT_TRUE(next.is_max());
4585 break;
4586 }
4587 objects.clear();
4588 current = next;
4589 }
4590 cerr << "listed.size() is " << listed.size() << std::endl;
4591 ASSERT_TRUE(listed.size() == created.size());
4592 for (set<ghobject_t>::iterator i = listed.begin();
4593 i != listed.end();
4594 ++i) {
4595 ASSERT_TRUE(created.count(*i));
4596 }
4597
4598 for (set<ghobject_t>::iterator i = created.begin();
4599 i != created.end();
4600 ++i) {
4601 ObjectStore::Transaction t;
4602 t.remove(cid, *i);
4603 r = apply_transaction(store, &osr, std::move(t));
4604 ASSERT_EQ(r, 0);
4605 }
4606 ObjectStore::Transaction t;
4607 t.remove_collection(cid);
4608 r = apply_transaction(store, &osr, std::move(t));
4609 ASSERT_EQ(r, 0);
4610}
4611
4612TEST_P(StoreTest, ScrubTest) {
4613 ObjectStore::Sequencer osr("test");
4614 int64_t poolid = 111;
4615 coll_t cid(spg_t(pg_t(0, poolid),shard_id_t(1)));
4616 int r;
4617 {
4618 ObjectStore::Transaction t;
4619 t.create_collection(cid, 0);
4620 r = apply_transaction(store, &osr, std::move(t));
4621 ASSERT_EQ(r, 0);
4622 }
4623 string base = "aaaaa";
4624 set<ghobject_t> created;
4625 for (int i = 0; i < 1000; ++i) {
4626 char buf[100];
4627 sprintf(buf, "%d", i);
4628 if (!(i % 5)) {
4629 cerr << "Object " << i << std::endl;
4630 }
4631 ghobject_t hoid(hobject_t(string(buf) + base, string(), CEPH_NOSNAP, i,
4632 poolid, ""),
4633 ghobject_t::NO_GEN, shard_id_t(1));
4634 {
4635 ObjectStore::Transaction t;
4636 t.touch(cid, hoid);
4637 r = apply_transaction(store, &osr, std::move(t));
4638 ASSERT_EQ(r, 0);
4639 }
4640 created.insert(hoid);
4641 }
4642
4643 // Add same hobject_t but different generation
4644 {
4645 ghobject_t hoid1(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""),
4646 ghobject_t::NO_GEN, shard_id_t(1));
4647 ghobject_t hoid2(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)1, shard_id_t(1));
4648 ghobject_t hoid3(hobject_t("same-object", string(), CEPH_NOSNAP, 0, poolid, ""), (gen_t)2, shard_id_t(1));
4649 ObjectStore::Transaction t;
4650 t.touch(cid, hoid1);
4651 t.touch(cid, hoid2);
4652 t.touch(cid, hoid3);
4653 r = apply_transaction(store, &osr, std::move(t));
4654 created.insert(hoid1);
4655 created.insert(hoid2);
4656 created.insert(hoid3);
4657 ASSERT_EQ(r, 0);
4658 }
4659
4660 vector<ghobject_t> objects;
4661 r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
4662 INT_MAX, &objects, 0);
4663 ASSERT_EQ(r, 0);
4664 set<ghobject_t> listed(objects.begin(), objects.end());
4665 cerr << "listed.size() is " << listed.size() << " and created.size() is " << created.size() << std::endl;
4666 ASSERT_TRUE(listed.size() == created.size());
4667 objects.clear();
4668 listed.clear();
4669 ghobject_t current, next;
4670 while (1) {
4671 r = store->collection_list(cid, current, ghobject_t::get_max(), 60,
4672 &objects, &next);
4673 ASSERT_EQ(r, 0);
4674 ASSERT_TRUE(sorted(objects));
4675 for (vector<ghobject_t>::iterator i = objects.begin();
4676 i != objects.end(); ++i) {
4677 if (listed.count(*i))
4678 cerr << *i << " repeated" << std::endl;
4679 listed.insert(*i);
4680 }
4681 if (objects.size() < 50) {
4682 ASSERT_TRUE(next.is_max());
4683 break;
4684 }
4685 objects.clear();
4686 current = next.get_boundary();
4687 }
4688 cerr << "listed.size() is " << listed.size() << std::endl;
4689 ASSERT_TRUE(listed.size() == created.size());
4690 for (set<ghobject_t>::iterator i = listed.begin();
4691 i != listed.end();
4692 ++i) {
4693 ASSERT_TRUE(created.count(*i));
4694 }
4695
4696 for (set<ghobject_t>::iterator i = created.begin();
4697 i != created.end();
4698 ++i) {
4699 ObjectStore::Transaction t;
4700 t.remove(cid, *i);
4701 r = apply_transaction(store, &osr, std::move(t));
4702 ASSERT_EQ(r, 0);
4703 }
4704 ObjectStore::Transaction t;
4705 t.remove_collection(cid);
4706 r = apply_transaction(store, &osr, std::move(t));
4707 ASSERT_EQ(r, 0);
4708}
4709
4710
4711TEST_P(StoreTest, OMapTest) {
4712 ObjectStore::Sequencer osr("test");
4713 coll_t cid;
4714 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
4715 int r;
4716 {
4717 ObjectStore::Transaction t;
4718 t.create_collection(cid, 0);
4719 r = apply_transaction(store, &osr, std::move(t));
4720 ASSERT_EQ(r, 0);
4721 }
4722
4723 map<string, bufferlist> attrs;
4724 {
4725 ObjectStore::Transaction t;
4726 t.touch(cid, hoid);
4727 t.omap_clear(cid, hoid);
4728 map<string, bufferlist> start_set;
4729 t.omap_setkeys(cid, hoid, start_set);
31f18b77
FG
4730 r = apply_transaction(store, &osr, std::move(t));
4731 ASSERT_EQ(r, 0);
7c673cae
FG
4732 }
4733
4734 for (int i = 0; i < 100; i++) {
4735 if (!(i%5)) {
4736 std::cout << "On iteration " << i << std::endl;
4737 }
4738 ObjectStore::Transaction t;
4739 bufferlist bl;
4740 map<string, bufferlist> cur_attrs;
4741 r = store->omap_get(cid, hoid, &bl, &cur_attrs);
4742 ASSERT_EQ(r, 0);
4743 for (map<string, bufferlist>::iterator j = attrs.begin();
4744 j != attrs.end();
4745 ++j) {
4746 bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
4747 if (!correct) {
4748 std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
4749 if (cur_attrs.count(j->first) > 0) {
4750 std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
4751 }
4752 }
4753 ASSERT_EQ(correct, true);
4754 }
4755 ASSERT_EQ(attrs.size(), cur_attrs.size());
4756
4757 char buf[100];
4758 snprintf(buf, sizeof(buf), "%d", i);
4759 bl.clear();
4760 bufferptr bp(buf, strlen(buf) + 1);
4761 bl.append(bp);
4762 map<string, bufferlist> to_add;
4763 to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4764 attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4765 t.omap_setkeys(cid, hoid, to_add);
31f18b77
FG
4766 r = apply_transaction(store, &osr, std::move(t));
4767 ASSERT_EQ(r, 0);
7c673cae
FG
4768 }
4769
4770 int i = 0;
4771 while (attrs.size()) {
4772 if (!(i%5)) {
4773 std::cout << "removal: On iteration " << i << std::endl;
4774 }
4775 ObjectStore::Transaction t;
4776 bufferlist bl;
4777 map<string, bufferlist> cur_attrs;
4778 r = store->omap_get(cid, hoid, &bl, &cur_attrs);
4779 ASSERT_EQ(r, 0);
4780 for (map<string, bufferlist>::iterator j = attrs.begin();
4781 j != attrs.end();
4782 ++j) {
4783 bool correct = cur_attrs.count(j->first) && string(cur_attrs[j->first].c_str()) == string(j->second.c_str());
4784 if (!correct) {
4785 std::cout << j->first << " is present in cur_attrs " << cur_attrs.count(j->first) << " times " << std::endl;
4786 if (cur_attrs.count(j->first) > 0) {
4787 std::cout << j->second.c_str() << " : " << cur_attrs[j->first].c_str() << std::endl;
4788 }
4789 }
4790 ASSERT_EQ(correct, true);
4791 }
4792
4793 string to_remove = attrs.begin()->first;
4794 set<string> keys_to_remove;
4795 keys_to_remove.insert(to_remove);
4796 t.omap_rmkeys(cid, hoid, keys_to_remove);
31f18b77
FG
4797 r = apply_transaction(store, &osr, std::move(t));
4798 ASSERT_EQ(r, 0);
7c673cae
FG
4799
4800 attrs.erase(to_remove);
4801
4802 ++i;
4803 }
4804
4805 {
4806 bufferlist bl1;
4807 bl1.append("omap_header");
4808 ObjectStore::Transaction t;
4809 t.omap_setheader(cid, hoid, bl1);
31f18b77
FG
4810 r = apply_transaction(store, &osr, std::move(t));
4811 ASSERT_EQ(r, 0);
7c673cae
FG
4812 t = ObjectStore::Transaction();
4813
4814 bufferlist bl2;
4815 bl2.append("value");
4816 map<string, bufferlist> to_add;
4817 to_add.insert(pair<string, bufferlist>("key", bl2));
4818 t.omap_setkeys(cid, hoid, to_add);
31f18b77
FG
4819 r = apply_transaction(store, &osr, std::move(t));
4820 ASSERT_EQ(r, 0);
7c673cae
FG
4821
4822 bufferlist bl3;
4823 map<string, bufferlist> cur_attrs;
4824 r = store->omap_get(cid, hoid, &bl3, &cur_attrs);
4825 ASSERT_EQ(r, 0);
4826 ASSERT_EQ(cur_attrs.size(), size_t(1));
4827 ASSERT_TRUE(bl_eq(bl1, bl3));
4828
4829 set<string> keys;
4830 r = store->omap_get_keys(cid, hoid, &keys);
4831 ASSERT_EQ(r, 0);
4832 ASSERT_EQ(keys.size(), size_t(1));
4833 }
4834
4835 // test omap_clear, omap_rmkey_range
4836 {
4837 {
4838 map<string,bufferlist> to_set;
4839 for (int n=0; n<10; ++n) {
4840 to_set[stringify(n)].append("foo");
4841 }
4842 bufferlist h;
4843 h.append("header");
4844 ObjectStore::Transaction t;
4845 t.remove(cid, hoid);
4846 t.touch(cid, hoid);
4847 t.omap_setheader(cid, hoid, h);
4848 t.omap_setkeys(cid, hoid, to_set);
31f18b77
FG
4849 r = apply_transaction(store, &osr, std::move(t));
4850 ASSERT_EQ(r, 0);
7c673cae
FG
4851 }
4852 {
4853 ObjectStore::Transaction t;
4854 t.omap_rmkeyrange(cid, hoid, "3", "7");
31f18b77
FG
4855 r = apply_transaction(store, &osr, std::move(t));
4856 ASSERT_EQ(r, 0);
7c673cae
FG
4857 }
4858 {
4859 bufferlist hdr;
4860 map<string,bufferlist> m;
4861 store->omap_get(cid, hoid, &hdr, &m);
4862 ASSERT_EQ(6u, hdr.length());
4863 ASSERT_TRUE(m.count("2"));
4864 ASSERT_TRUE(!m.count("3"));
4865 ASSERT_TRUE(!m.count("6"));
4866 ASSERT_TRUE(m.count("7"));
4867 ASSERT_TRUE(m.count("8"));
4868 //cout << m << std::endl;
4869 ASSERT_EQ(6u, m.size());
4870 }
4871 {
4872 ObjectStore::Transaction t;
4873 t.omap_clear(cid, hoid);
31f18b77
FG
4874 r = apply_transaction(store, &osr, std::move(t));
4875 ASSERT_EQ(r, 0);
7c673cae
FG
4876 }
4877 {
4878 bufferlist hdr;
4879 map<string,bufferlist> m;
4880 store->omap_get(cid, hoid, &hdr, &m);
4881 ASSERT_EQ(0u, hdr.length());
4882 ASSERT_EQ(0u, m.size());
4883 }
4884 }
4885
4886 ObjectStore::Transaction t;
4887 t.remove(cid, hoid);
4888 t.remove_collection(cid);
4889 r = apply_transaction(store, &osr, std::move(t));
4890 ASSERT_EQ(r, 0);
4891}
4892
4893TEST_P(StoreTest, OMapIterator) {
4894 ObjectStore::Sequencer osr("test");
4895 coll_t cid;
4896 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
4897 int count = 0;
4898 int r;
4899 {
4900 ObjectStore::Transaction t;
4901 t.create_collection(cid, 0);
4902 r = apply_transaction(store, &osr, std::move(t));
4903 ASSERT_EQ(r, 0);
4904 }
4905
4906 map<string, bufferlist> attrs;
4907 {
4908 ObjectStore::Transaction t;
4909 t.touch(cid, hoid);
4910 t.omap_clear(cid, hoid);
4911 map<string, bufferlist> start_set;
4912 t.omap_setkeys(cid, hoid, start_set);
31f18b77
FG
4913 r = apply_transaction(store, &osr, std::move(t));
4914 ASSERT_EQ(r, 0);
7c673cae
FG
4915 }
4916 ObjectMap::ObjectMapIterator iter;
4917 bool correct;
4918 //basic iteration
4919 for (int i = 0; i < 100; i++) {
4920 if (!(i%5)) {
4921 std::cout << "On iteration " << i << std::endl;
4922 }
4923 bufferlist bl;
4924
4925 // FileStore may deadlock two active iterators over the same data
4926 iter = ObjectMap::ObjectMapIterator();
4927
4928 iter = store->get_omap_iterator(cid, hoid);
4929 for (iter->seek_to_first(), count=0; iter->valid(); iter->next(), count++) {
4930 string key = iter->key();
4931 bufferlist value = iter->value();
4932 correct = attrs.count(key) && (string(value.c_str()) == string(attrs[key].c_str()));
4933 if (!correct) {
4934 if (attrs.count(key) > 0) {
4935 std::cout << "key " << key << "in omap , " << value.c_str() << " : " << attrs[key].c_str() << std::endl;
4936 }
4937 else
4938 std::cout << "key " << key << "should not exists in omap" << std::endl;
4939 }
4940 ASSERT_EQ(correct, true);
4941 }
4942 ASSERT_EQ((int)attrs.size(), count);
4943
4944 // FileStore may deadlock an active iterator vs apply_transaction
4945 iter = ObjectMap::ObjectMapIterator();
4946
4947 char buf[100];
4948 snprintf(buf, sizeof(buf), "%d", i);
4949 bl.clear();
4950 bufferptr bp(buf, strlen(buf) + 1);
4951 bl.append(bp);
4952 map<string, bufferlist> to_add;
4953 to_add.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4954 attrs.insert(pair<string, bufferlist>("key-" + string(buf), bl));
4955 ObjectStore::Transaction t;
4956 t.omap_setkeys(cid, hoid, to_add);
31f18b77
FG
4957 r = apply_transaction(store, &osr, std::move(t));
4958 ASSERT_EQ(r, 0);
7c673cae
FG
4959 }
4960
4961 iter = store->get_omap_iterator(cid, hoid);
4962 //lower bound
4963 string bound_key = "key-5";
4964 iter->lower_bound(bound_key);
4965 correct = bound_key <= iter->key();
4966 if (!correct) {
4967 std::cout << "lower bound, bound key is " << bound_key << " < iter key is " << iter->key() << std::endl;
4968 }
4969 ASSERT_EQ(correct, true);
4970 //upper bound
4971 iter->upper_bound(bound_key);
4972 correct = iter->key() > bound_key;
4973 if (!correct) {
4974 std::cout << "upper bound, bound key is " << bound_key << " >= iter key is " << iter->key() << std::endl;
4975 }
4976 ASSERT_EQ(correct, true);
4977
4978 // FileStore may deadlock an active iterator vs apply_transaction
4979 iter = ObjectMap::ObjectMapIterator();
4980 {
4981 ObjectStore::Transaction t;
4982 t.remove(cid, hoid);
4983 t.remove_collection(cid);
4984 r = apply_transaction(store, &osr, std::move(t));
4985 ASSERT_EQ(r, 0);
4986 }
4987}
4988
4989TEST_P(StoreTest, XattrTest) {
4990 ObjectStore::Sequencer osr("test");
4991 coll_t cid;
4992 ghobject_t hoid(hobject_t("tesomap", "", CEPH_NOSNAP, 0, 0, ""));
4993 bufferlist big;
4994 for (unsigned i = 0; i < 10000; ++i) {
4995 big.append('\0');
4996 }
4997 bufferlist small;
4998 for (unsigned i = 0; i < 10; ++i) {
4999 small.append('\0');
5000 }
5001 int r;
5002 {
5003 ObjectStore::Transaction t;
5004 t.create_collection(cid, 0);
5005 t.touch(cid, hoid);
5006 r = apply_transaction(store, &osr, std::move(t));
5007 ASSERT_EQ(r, 0);
5008 }
5009
5010 map<string, bufferlist> attrs;
5011 {
5012 ObjectStore::Transaction t;
5013 t.setattr(cid, hoid, "attr1", small);
5014 attrs["attr1"] = small;
5015 t.setattr(cid, hoid, "attr2", big);
5016 attrs["attr2"] = big;
5017 t.setattr(cid, hoid, "attr3", small);
5018 attrs["attr3"] = small;
5019 t.setattr(cid, hoid, "attr1", small);
5020 attrs["attr1"] = small;
5021 t.setattr(cid, hoid, "attr4", big);
5022 attrs["attr4"] = big;
5023 t.setattr(cid, hoid, "attr3", big);
5024 attrs["attr3"] = big;
5025 r = apply_transaction(store, &osr, std::move(t));
5026 ASSERT_EQ(r, 0);
5027 }
5028
5029 map<string, bufferptr> aset;
5030 store->getattrs(cid, hoid, aset);
5031 ASSERT_EQ(aset.size(), attrs.size());
5032 for (map<string, bufferptr>::iterator i = aset.begin();
5033 i != aset.end();
5034 ++i) {
5035 bufferlist bl;
5036 bl.push_back(i->second);
5037 ASSERT_TRUE(attrs[i->first] == bl);
5038 }
5039
5040 {
5041 ObjectStore::Transaction t;
5042 t.rmattr(cid, hoid, "attr2");
5043 attrs.erase("attr2");
5044 r = apply_transaction(store, &osr, std::move(t));
5045 ASSERT_EQ(r, 0);
5046 }
5047
5048 aset.clear();
5049 store->getattrs(cid, hoid, aset);
5050 ASSERT_EQ(aset.size(), attrs.size());
5051 for (map<string, bufferptr>::iterator i = aset.begin();
5052 i != aset.end();
5053 ++i) {
5054 bufferlist bl;
5055 bl.push_back(i->second);
5056 ASSERT_TRUE(attrs[i->first] == bl);
5057 }
5058
5059 bufferptr bp;
5060 r = store->getattr(cid, hoid, "attr2", bp);
5061 ASSERT_EQ(r, -ENODATA);
5062
5063 r = store->getattr(cid, hoid, "attr3", bp);
5064 ASSERT_EQ(r, 0);
5065 bufferlist bl2;
5066 bl2.push_back(bp);
5067 ASSERT_TRUE(bl2 == attrs["attr3"]);
5068
5069 ObjectStore::Transaction t;
5070 t.remove(cid, hoid);
5071 t.remove_collection(cid);
5072 r = apply_transaction(store, &osr, std::move(t));
5073 ASSERT_EQ(r, 0);
5074}
5075
5076void colsplittest(
5077 ObjectStore *store,
5078 unsigned num_objects,
5079 unsigned common_suffix_size,
5080 bool clones
5081 ) {
5082 ObjectStore::Sequencer osr("test");
5083 coll_t cid(spg_t(pg_t(0,52),shard_id_t::NO_SHARD));
5084 coll_t tid(spg_t(pg_t(1<<common_suffix_size,52),shard_id_t::NO_SHARD));
5085 int r = 0;
5086 {
5087 ObjectStore::Transaction t;
5088 t.create_collection(cid, common_suffix_size);
5089 r = apply_transaction(store, &osr, std::move(t));
5090 ASSERT_EQ(r, 0);
5091 }
5092 bufferlist small;
5093 small.append("small");
5094 {
5095 ObjectStore::Transaction t;
5096 for (uint32_t i = 0; i < (2 - (int)clones)*num_objects; ++i) {
5097 stringstream objname;
5098 objname << "obj" << i;
5099 ghobject_t a(hobject_t(
5100 objname.str(),
5101 "",
5102 CEPH_NOSNAP,
5103 i<<common_suffix_size,
5104 52, ""));
5105 t.write(cid, a, 0, small.length(), small,
5106 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5107 if (clones) {
5108 objname << "-clone";
5109 ghobject_t b(hobject_t(
5110 objname.str(),
5111 "",
5112 CEPH_NOSNAP,
5113 i<<common_suffix_size,
5114 52, ""));
5115 t.clone(cid, a, b);
5116 }
5117 if (i % 100) {
5118 r = apply_transaction(store, &osr, std::move(t));
5119 ASSERT_EQ(r, 0);
5120 t = ObjectStore::Transaction();
5121 }
5122 }
5123 r = apply_transaction(store, &osr, std::move(t));
5124 ASSERT_EQ(r, 0);
5125 }
5126 {
5127 ObjectStore::Transaction t;
5128 t.create_collection(tid, common_suffix_size + 1);
5129 t.split_collection(cid, common_suffix_size+1, 1<<common_suffix_size, tid);
5130 r = apply_transaction(store, &osr, std::move(t));
5131 ASSERT_EQ(r, 0);
5132 }
5133
5134 ObjectStore::Transaction t;
5135 vector<ghobject_t> objects;
5136 r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
5137 INT_MAX, &objects, 0);
5138 ASSERT_EQ(r, 0);
5139 ASSERT_EQ(objects.size(), num_objects);
5140 unsigned size = 0;
5141 for (vector<ghobject_t>::iterator i = objects.begin();
5142 i != objects.end();
5143 ++i) {
5144 ASSERT_EQ(!!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
5145 t.remove(cid, *i);
5146 if (++size > 100) {
5147 size = 0;
5148 r = apply_transaction(store, &osr, std::move(t));
5149 ASSERT_EQ(r, 0);
5150 t = ObjectStore::Transaction();
5151 }
5152 }
5153
5154 objects.clear();
5155 r = store->collection_list(tid, ghobject_t(), ghobject_t::get_max(),
5156 INT_MAX, &objects, 0);
5157 ASSERT_EQ(r, 0);
5158 ASSERT_EQ(objects.size(), num_objects);
5159 for (vector<ghobject_t>::iterator i = objects.begin();
5160 i != objects.end();
5161 ++i) {
5162 ASSERT_EQ(!(i->hobj.get_hash() & (1<<common_suffix_size)), 0u);
5163 t.remove(tid, *i);
5164 if (++size > 100) {
5165 size = 0;
5166 r = apply_transaction(store, &osr, std::move(t));
5167 ASSERT_EQ(r, 0);
5168 t = ObjectStore::Transaction();
5169 }
5170 }
5171
5172 t.remove_collection(cid);
5173 t.remove_collection(tid);
5174 r = apply_transaction(store, &osr, std::move(t));
5175 ASSERT_EQ(r, 0);
5176}
5177
5178TEST_P(StoreTest, ColSplitTest1) {
5179 colsplittest(store.get(), 10000, 11, false);
5180}
5181TEST_P(StoreTest, ColSplitTest1Clones) {
5182 colsplittest(store.get(), 10000, 11, true);
5183}
5184TEST_P(StoreTest, ColSplitTest2) {
5185 colsplittest(store.get(), 100, 7, false);
5186}
5187TEST_P(StoreTest, ColSplitTest2Clones) {
5188 colsplittest(store.get(), 100, 7, true);
5189}
5190
5191#if 0
5192TEST_P(StoreTest, ColSplitTest3) {
5193 colsplittest(store.get(), 100000, 25);
5194}
5195#endif
5196
5197/**
5198 * This test tests adding two different groups
5199 * of objects, each with 1 common prefix and 1
5200 * different prefix. We then remove half
5201 * in order to verify that the merging correctly
5202 * stops at the common prefix subdir. See bug
5203 * #5273 */
5204TEST_P(StoreTest, TwoHash) {
5205 ObjectStore::Sequencer osr("test");
5206 coll_t cid;
5207 int r;
5208 {
5209 ObjectStore::Transaction t;
5210 t.create_collection(cid, 0);
5211 r = apply_transaction(store, &osr, std::move(t));
5212 ASSERT_EQ(r, 0);
5213 }
5214 std::cout << "Making objects" << std::endl;
5215 for (int i = 0; i < 360; ++i) {
5216 ObjectStore::Transaction t;
5217 ghobject_t o;
5218 o.hobj.pool = -1;
5219 if (i < 8) {
5220 o.hobj.set_hash((i << 16) | 0xA1);
5221 t.touch(cid, o);
5222 }
5223 o.hobj.set_hash((i << 16) | 0xB1);
5224 t.touch(cid, o);
5225 r = apply_transaction(store, &osr, std::move(t));
5226 ASSERT_EQ(r, 0);
5227 }
5228 std::cout << "Removing half" << std::endl;
5229 for (int i = 1; i < 8; ++i) {
5230 ObjectStore::Transaction t;
5231 ghobject_t o;
5232 o.hobj.pool = -1;
5233 o.hobj.set_hash((i << 16) | 0xA1);
5234 t.remove(cid, o);
5235 r = apply_transaction(store, &osr, std::move(t));
5236 ASSERT_EQ(r, 0);
5237 }
5238 std::cout << "Checking" << std::endl;
5239 for (int i = 1; i < 8; ++i) {
5240 ObjectStore::Transaction t;
5241 ghobject_t o;
5242 o.hobj.set_hash((i << 16) | 0xA1);
5243 o.hobj.pool = -1;
5244 bool exists = store->exists(cid, o);
5245 ASSERT_EQ(exists, false);
5246 }
5247 {
5248 ghobject_t o;
5249 o.hobj.set_hash(0xA1);
5250 o.hobj.pool = -1;
5251 bool exists = store->exists(cid, o);
5252 ASSERT_EQ(exists, true);
5253 }
5254 std::cout << "Cleanup" << std::endl;
5255 for (int i = 0; i < 360; ++i) {
5256 ObjectStore::Transaction t;
5257 ghobject_t o;
5258 o.hobj.set_hash((i << 16) | 0xA1);
5259 o.hobj.pool = -1;
5260 t.remove(cid, o);
5261 o.hobj.set_hash((i << 16) | 0xB1);
5262 t.remove(cid, o);
5263 r = apply_transaction(store, &osr, std::move(t));
5264 ASSERT_EQ(r, 0);
5265 }
5266 ObjectStore::Transaction t;
5267 t.remove_collection(cid);
5268 r = apply_transaction(store, &osr, std::move(t));
5269 ASSERT_EQ(r, 0);
5270}
5271
5272TEST_P(StoreTest, Rename) {
5273 ObjectStore::Sequencer osr("test");
5274 coll_t cid(spg_t(pg_t(0, 2122),shard_id_t::NO_SHARD));
5275 ghobject_t srcoid(hobject_t("src_oid", "", CEPH_NOSNAP, 0, 0, ""));
5276 ghobject_t dstoid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
5277 bufferlist a, b;
5278 a.append("foo");
5279 b.append("bar");
5280 int r;
5281 {
5282 ObjectStore::Transaction t;
5283 t.create_collection(cid, 0);
5284 t.write(cid, srcoid, 0, a.length(), a);
5285 r = apply_transaction(store, &osr, std::move(t));
5286 ASSERT_EQ(r, 0);
5287 }
5288 ASSERT_TRUE(store->exists(cid, srcoid));
5289 {
5290 ObjectStore::Transaction t;
5291 t.collection_move_rename(cid, srcoid, cid, dstoid);
5292 t.write(cid, srcoid, 0, b.length(), b);
5293 t.setattr(cid, srcoid, "attr", b);
5294 r = apply_transaction(store, &osr, std::move(t));
5295 ASSERT_EQ(r, 0);
5296 }
5297 ASSERT_TRUE(store->exists(cid, srcoid));
5298 ASSERT_TRUE(store->exists(cid, dstoid));
5299 {
5300 bufferlist bl;
5301 store->read(cid, srcoid, 0, 3, bl);
5302 ASSERT_TRUE(bl_eq(b, bl));
5303 store->read(cid, dstoid, 0, 3, bl);
5304 ASSERT_TRUE(bl_eq(a, bl));
5305 }
5306 {
5307 ObjectStore::Transaction t;
5308 t.remove(cid, dstoid);
5309 t.collection_move_rename(cid, srcoid, cid, dstoid);
5310 r = apply_transaction(store, &osr, std::move(t));
5311 ASSERT_EQ(r, 0);
5312 }
5313 ASSERT_TRUE(store->exists(cid, dstoid));
5314 ASSERT_FALSE(store->exists(cid, srcoid));
5315 {
5316 bufferlist bl;
5317 store->read(cid, dstoid, 0, 3, bl);
5318 ASSERT_TRUE(bl_eq(b, bl));
5319 }
5320 {
5321 ObjectStore::Transaction t;
5322 t.remove(cid, dstoid);
5323 t.remove_collection(cid);
5324 r = apply_transaction(store, &osr, std::move(t));
5325 ASSERT_EQ(r, 0);
5326 }
5327}
5328
5329TEST_P(StoreTest, MoveRename) {
5330 ObjectStore::Sequencer osr("test");
5331 coll_t cid(spg_t(pg_t(0, 212),shard_id_t::NO_SHARD));
5332 ghobject_t temp_oid(hobject_t("tmp_oid", "", CEPH_NOSNAP, 0, 0, ""));
5333 ghobject_t oid(hobject_t("dest_oid", "", CEPH_NOSNAP, 0, 0, ""));
5334 int r;
5335 {
5336 ObjectStore::Transaction t;
5337 t.create_collection(cid, 0);
5338 t.touch(cid, oid);
5339 r = apply_transaction(store, &osr, std::move(t));
5340 ASSERT_EQ(r, 0);
5341 }
5342 ASSERT_TRUE(store->exists(cid, oid));
5343 bufferlist data, attr;
5344 map<string, bufferlist> omap;
5345 data.append("data payload");
5346 attr.append("attr value");
5347 omap["omap_key"].append("omap value");
5348 {
5349 ObjectStore::Transaction t;
5350 t.touch(cid, temp_oid);
5351 t.write(cid, temp_oid, 0, data.length(), data);
5352 t.setattr(cid, temp_oid, "attr", attr);
5353 t.omap_setkeys(cid, temp_oid, omap);
5354 r = apply_transaction(store, &osr, std::move(t));
5355 ASSERT_EQ(r, 0);
5356 }
5357 ASSERT_TRUE(store->exists(cid, temp_oid));
5358 {
5359 ObjectStore::Transaction t;
5360 t.remove(cid, oid);
5361 t.collection_move_rename(cid, temp_oid, cid, oid);
5362 r = apply_transaction(store, &osr, std::move(t));
5363 ASSERT_EQ(r, 0);
5364 }
5365 ASSERT_TRUE(store->exists(cid, oid));
5366 ASSERT_FALSE(store->exists(cid, temp_oid));
5367 {
5368 bufferlist newdata;
5369 r = store->read(cid, oid, 0, 1000, newdata);
5370 ASSERT_GE(r, 0);
5371 ASSERT_TRUE(bl_eq(data, newdata));
5372 bufferlist newattr;
5373 r = store->getattr(cid, oid, "attr", newattr);
5374 ASSERT_EQ(r, 0);
5375 ASSERT_TRUE(bl_eq(attr, newattr));
5376 set<string> keys;
5377 keys.insert("omap_key");
5378 map<string, bufferlist> newomap;
5379 r = store->omap_get_values(cid, oid, keys, &newomap);
5380 ASSERT_GE(r, 0);
5381 ASSERT_EQ(1u, newomap.size());
5382 ASSERT_TRUE(newomap.count("omap_key"));
5383 ASSERT_TRUE(bl_eq(omap["omap_key"], newomap["omap_key"]));
5384 }
5385 {
5386 ObjectStore::Transaction t;
5387 t.remove(cid, oid);
5388 t.remove_collection(cid);
5389 r = apply_transaction(store, &osr, std::move(t));
5390 ASSERT_EQ(r, 0);
5391 }
5392}
5393
5394TEST_P(StoreTest, BigRGWObjectName) {
5395 ObjectStore::Sequencer osr("test");
5396 coll_t cid(spg_t(pg_t(0,12),shard_id_t::NO_SHARD));
5397 ghobject_t oid(
5398 hobject_t(
5399 "default.4106.50_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
5400 "",
5401 CEPH_NOSNAP,
5402 0x81920472,
5403 12,
5404 ""),
5405 15,
5406 shard_id_t::NO_SHARD);
5407 ghobject_t oid2(oid);
5408 oid2.generation = 17;
5409 ghobject_t oidhead(oid);
5410 oidhead.generation = ghobject_t::NO_GEN;
5411
5412 int r;
5413 {
5414 ObjectStore::Transaction t;
5415 t.create_collection(cid, 0);
5416 t.touch(cid, oidhead);
5417 t.collection_move_rename(cid, oidhead, cid, oid);
5418 t.touch(cid, oidhead);
5419 t.collection_move_rename(cid, oidhead, cid, oid2);
5420 r = apply_transaction(store, &osr, std::move(t));
5421 ASSERT_EQ(r, 0);
5422 }
5423
5424 {
5425 ObjectStore::Transaction t;
5426 t.remove(cid, oid);
5427 r = apply_transaction(store, &osr, std::move(t));
5428 ASSERT_EQ(r, 0);
5429 }
5430
5431 {
5432 vector<ghobject_t> objects;
5433 r = store->collection_list(cid, ghobject_t(), ghobject_t::get_max(),
5434 INT_MAX, &objects, 0);
5435 ASSERT_EQ(r, 0);
5436 ASSERT_EQ(objects.size(), 1u);
5437 ASSERT_EQ(objects[0], oid2);
5438 }
5439
5440 ASSERT_FALSE(store->exists(cid, oid));
5441
5442 {
5443 ObjectStore::Transaction t;
5444 t.remove(cid, oid2);
5445 t.remove_collection(cid);
5446 r = apply_transaction(store, &osr, std::move(t));
5447 ASSERT_EQ(r, 0);
5448
5449 }
5450}
5451
5452TEST_P(StoreTest, SetAllocHint) {
5453 ObjectStore::Sequencer osr("test");
5454 coll_t cid;
5455 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, 0, ""));
5456 int r;
5457 {
5458 ObjectStore::Transaction t;
5459 t.create_collection(cid, 0);
5460 t.touch(cid, hoid);
5461 r = apply_transaction(store, &osr, std::move(t));
5462 ASSERT_EQ(r, 0);
5463 }
5464 {
5465 ObjectStore::Transaction t;
5466 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
5467 r = apply_transaction(store, &osr, std::move(t));
5468 ASSERT_EQ(r, 0);
5469 }
5470 {
5471 ObjectStore::Transaction t;
5472 t.remove(cid, hoid);
5473 r = apply_transaction(store, &osr, std::move(t));
5474 ASSERT_EQ(r, 0);
5475 }
5476 {
5477 ObjectStore::Transaction t;
5478 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*4, 0);
5479 r = apply_transaction(store, &osr, std::move(t));
5480 ASSERT_EQ(r, 0);
5481 }
5482 {
5483 ObjectStore::Transaction t;
5484 t.remove_collection(cid);
5485 r = apply_transaction(store, &osr, std::move(t));
5486 ASSERT_EQ(r, 0);
5487 }
5488}
5489
5490TEST_P(StoreTest, TryMoveRename) {
5491 ObjectStore::Sequencer osr("test");
5492 coll_t cid;
5493 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
5494 ghobject_t hoid2(hobject_t("test_hint2", "", CEPH_NOSNAP, 0, -1, ""));
5495 int r;
5496 {
5497 ObjectStore::Transaction t;
5498 t.create_collection(cid, 0);
5499 r = apply_transaction(store, &osr, std::move(t));
5500 ASSERT_EQ(r, 0);
5501 }
5502 {
5503 ObjectStore::Transaction t;
5504 t.try_rename(cid, hoid, hoid2);
5505 r = apply_transaction(store, &osr, std::move(t));
5506 ASSERT_EQ(r, 0);
5507 }
5508 {
5509 ObjectStore::Transaction t;
5510 t.touch(cid, hoid);
5511 r = apply_transaction(store, &osr, std::move(t));
5512 ASSERT_EQ(r, 0);
5513 }
5514 {
5515 ObjectStore::Transaction t;
5516 t.try_rename(cid, hoid, hoid2);
5517 r = apply_transaction(store, &osr, std::move(t));
5518 ASSERT_EQ(r, 0);
5519 }
5520 struct stat st;
5521 ASSERT_EQ(store->stat(cid, hoid, &st), -ENOENT);
5522 ASSERT_EQ(store->stat(cid, hoid2, &st), 0);
5523}
5524
5525#if defined(HAVE_LIBAIO)
5526TEST_P(StoreTest, BluestoreOnOffCSumTest) {
5527 if (string(GetParam()) != "bluestore")
5528 return;
5529 g_conf->set_val("bluestore_csum_type", "crc32c");
5530 g_conf->apply_changes(NULL);
5531
5532 ObjectStore::Sequencer osr("test");
5533 int r;
5534 coll_t cid;
5535 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
5536 {
5537 bufferlist in;
5538 r = store->read(cid, hoid, 0, 5, in);
5539 ASSERT_EQ(-ENOENT, r);
5540 }
5541 {
5542 ObjectStore::Transaction t;
5543 t.create_collection(cid, 0);
5544 cerr << "Creating collection " << cid << std::endl;
5545 r = apply_transaction(store, &osr, std::move(t));
5546 ASSERT_EQ(r, 0);
5547 }
5548 {
5549 //write with csum enabled followed by read with csum disabled
5550 size_t block_size = 64*1024;
5551 ObjectStore::Transaction t;
5552 bufferlist bl, orig;
5553 bl.append(std::string(block_size, 'a'));
5554 orig = bl;
5555 t.remove(cid, hoid);
5556 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
5557 t.write(cid, hoid, 0, bl.length(), bl);
5558 cerr << "Remove then create" << std::endl;
5559 r = apply_transaction(store, &osr, std::move(t));
5560 ASSERT_EQ(r, 0);
5561
5562 g_conf->set_val("bluestore_csum_type", "none");
5563 g_conf->apply_changes(NULL);
5564
5565 bufferlist in;
5566 r = store->read(cid, hoid, 0, block_size, in);
5567 ASSERT_EQ((int)block_size, r);
5568 ASSERT_TRUE(bl_eq(orig, in));
5569
5570 }
5571 {
5572 //write with csum disabled followed by read with csum enabled
5573
5574 size_t block_size = 64*1024;
5575 ObjectStore::Transaction t;
5576 bufferlist bl, orig;
5577 bl.append(std::string(block_size, 'a'));
5578 orig = bl;
5579 t.remove(cid, hoid);
5580 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
5581 t.write(cid, hoid, 0, bl.length(), bl);
5582 cerr << "Remove then create" << std::endl;
5583 r = apply_transaction(store, &osr, std::move(t));
5584 ASSERT_EQ(r, 0);
5585
5586 g_conf->set_val("bluestore_csum_type", "crc32c");
5587 g_conf->apply_changes(NULL);
5588
5589 bufferlist in;
5590 r = store->read(cid, hoid, 0, block_size, in);
5591 ASSERT_EQ((int)block_size, r);
5592 ASSERT_TRUE(bl_eq(orig, in));
5593 }
5594 {
5595 //'mixed' non-overlapping writes to the same blob
5596
5597 ObjectStore::Transaction t;
5598 bufferlist bl, orig;
5599 size_t block_size = 8000;
5600 bl.append(std::string(block_size, 'a'));
5601 orig = bl;
5602 t.remove(cid, hoid);
5603 t.write(cid, hoid, 0, bl.length(), bl);
5604 cerr << "Remove then create" << std::endl;
5605 r = apply_transaction(store, &osr, std::move(t));
5606 ASSERT_EQ(r, 0);
5607
5608 g_conf->set_val("bluestore_csum_type", "none");
5609 g_conf->apply_changes(NULL);
5610
5611 ObjectStore::Transaction t2;
5612 t2.write(cid, hoid, block_size*2, bl.length(), bl);
5613 cerr << "Append 'unprotected'" << std::endl;
5614 r = apply_transaction(store, &osr, std::move(t2));
5615 ASSERT_EQ(r, 0);
5616
5617 bufferlist in;
5618 r = store->read(cid, hoid, 0, block_size, in);
5619 ASSERT_EQ((int)block_size, r);
5620 ASSERT_TRUE(bl_eq(orig, in));
5621 in.clear();
5622 r = store->read(cid, hoid, block_size*2, block_size, in);
5623 ASSERT_EQ((int)block_size, r);
5624 ASSERT_TRUE(bl_eq(orig, in));
5625
5626 g_conf->set_val("bluestore_csum_type", "crc32c");
5627 g_conf->apply_changes(NULL);
5628 in.clear();
5629 r = store->read(cid, hoid, 0, block_size, in);
5630 ASSERT_EQ((int)block_size, r);
5631 ASSERT_TRUE(bl_eq(orig, in));
5632 in.clear();
5633 r = store->read(cid, hoid, block_size*2, block_size, in);
5634 ASSERT_EQ((int)block_size, r);
5635 ASSERT_TRUE(bl_eq(orig, in));
5636 }
5637 {
5638 //partially blob overwrite under a different csum enablement mode
5639
5640 ObjectStore::Transaction t;
5641 bufferlist bl, orig, orig2;
5642 size_t block_size0 = 0x10000;
5643 size_t block_size = 9000;
5644 size_t block_size2 = 5000;
5645 bl.append(std::string(block_size0, 'a'));
5646 t.remove(cid, hoid);
5647 t.set_alloc_hint(cid, hoid, 4*1024*1024, 1024*8, 0);
5648 t.write(cid, hoid, 0, bl.length(), bl);
5649 cerr << "Remove then create" << std::endl;
5650 r = apply_transaction(store, &osr, std::move(t));
5651 ASSERT_EQ(r, 0);
5652
5653 g_conf->set_val("bluestore_csum_type", "none");
5654 g_conf->apply_changes(NULL);
5655
5656 ObjectStore::Transaction t2;
5657 bl.clear();
5658 bl.append(std::string(block_size, 'b'));
5659 t2.write(cid, hoid, 0, bl.length(), bl);
5660 t2.write(cid, hoid, block_size0, bl.length(), bl);
5661 cerr << "Overwrite with unprotected data" << std::endl;
5662 r = apply_transaction(store, &osr, std::move(t2));
5663 ASSERT_EQ(r, 0);
5664
5665 orig = bl;
5666 orig2 = bl;
5667 orig.append( std::string(block_size0 - block_size, 'a'));
5668
5669 bufferlist in;
5670 r = store->read(cid, hoid, 0, block_size0, in);
5671 ASSERT_EQ((int)block_size0, r);
5672 ASSERT_TRUE(bl_eq(orig, in));
5673
5674 r = store->read(cid, hoid, block_size0, block_size, in);
5675 ASSERT_EQ((int)block_size, r);
5676 ASSERT_TRUE(bl_eq(orig2, in));
5677
5678 g_conf->set_val("bluestore_csum_type", "crc32c");
5679 g_conf->apply_changes(NULL);
5680
5681 ObjectStore::Transaction t3;
5682 bl.clear();
5683 bl.append(std::string(block_size2, 'c'));
5684 t3.write(cid, hoid, block_size0, bl.length(), bl);
5685 cerr << "Overwrite with protected data" << std::endl;
5686 r = apply_transaction(store, &osr, std::move(t3));
5687 ASSERT_EQ(r, 0);
5688
5689 in.clear();
5690 orig = bl;
5691 orig.append( std::string(block_size - block_size2, 'b'));
5692 r = store->read(cid, hoid, block_size0, block_size, in);
5693 ASSERT_EQ((int)block_size, r);
5694 ASSERT_TRUE(bl_eq(orig, in));
5695 }
5696
5697 {
5698 ObjectStore::Transaction t;
5699 t.remove(cid, hoid);
5700 t.remove_collection(cid);
5701 cerr << "Cleaning" << std::endl;
5702 r = apply_transaction(store, &osr, std::move(t));
5703 ASSERT_EQ(r, 0);
5704 }
5705}
5706#endif
5707
5708INSTANTIATE_TEST_CASE_P(
5709 ObjectStore,
5710 StoreTest,
5711 ::testing::Values(
5712 "memstore",
5713 "filestore",
5714#if defined(HAVE_LIBAIO)
5715 "bluestore",
5716#endif
5717 "kstore"));
5718
5719// Note: instantiate all stores to preserve store numbering order only
5720INSTANTIATE_TEST_CASE_P(
5721 ObjectStore,
5722 StoreTestSpecificAUSize,
5723 ::testing::Values(
5724 "memstore",
5725 "filestore",
5726#if defined(HAVE_LIBAIO)
5727 "bluestore",
5728#endif
5729 "kstore"));
5730
5731#else
5732
5733// Google Test may not support value-parameterized tests with some
5734// compilers. If we use conditional compilation to compile out all
5735// code referring to the gtest_main library, MSVC linker will not link
5736// that library at all and consequently complain about missing entry
5737// point defined in that library (fatal error LNK1561: entry point
5738// must be defined). This dummy test keeps gtest_main linked in.
5739TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
5740
5741#endif
5742
5743void doMany4KWritesTest(boost::scoped_ptr<ObjectStore>& store,
5744 unsigned max_objects,
5745 unsigned max_ops,
5746 unsigned max_object_size,
5747 unsigned max_write_size,
5748 unsigned write_alignment,
5749 store_statfs_t* res_stat)
5750{
5751 ObjectStore::Sequencer osr("test");
5752 MixedGenerator gen(555);
5753 gen_type rng(time(NULL));
5754 coll_t cid(spg_t(pg_t(0,555), shard_id_t::NO_SHARD));
5755
5756 SyntheticWorkloadState test_obj(store.get(),
5757 &gen,
5758 &rng,
5759 &osr,
5760 cid,
5761 max_object_size,
5762 max_write_size,
5763 write_alignment);
5764 test_obj.init();
5765 for (unsigned i = 0; i < max_objects; ++i) {
5766 if (!(i % 500)) cerr << "seeding object " << i << std::endl;
5767 test_obj.touch();
5768 }
5769 for (unsigned i = 0; i < max_ops; ++i) {
5770 if (!(i % 200)) {
5771 cerr << "Op " << i << std::endl;
5772 test_obj.print_internal_state();
5773 }
5774 test_obj.write();
5775 }
5776 test_obj.wait_for_done();
5777 if (res_stat) {
5778 test_obj.statfs(*res_stat);
5779 }
5780 test_obj.shutdown();
5781}
5782
5783TEST_P(StoreTestSpecificAUSize, Many4KWritesTest) {
5784 if (string(GetParam()) != "bluestore")
5785 return;
5786
5787 StartDeferred(0x10000);
5788
5789 store_statfs_t res_stat;
5790 unsigned max_object = 4*1024*1024;
5791
5792 doMany4KWritesTest(store, 1, 1000, 4*1024*1024, 4*1024, 0, &res_stat);
5793
5794 ASSERT_LE(res_stat.stored, max_object);
5795 ASSERT_EQ(res_stat.allocated, max_object);
5796}
5797
5798TEST_P(StoreTestSpecificAUSize, Many4KWritesNoCSumTest) {
5799 if (string(GetParam()) != "bluestore")
5800 return;
5801 StartDeferred(0x10000);
5802 g_conf->set_val("bluestore_csum_type", "none");
5803 g_ceph_context->_conf->apply_changes(NULL);
5804 store_statfs_t res_stat;
5805 unsigned max_object = 4*1024*1024;
5806
5807 doMany4KWritesTest(store, 1, 1000, max_object, 4*1024, 0, &res_stat );
5808
5809 ASSERT_LE(res_stat.stored, max_object);
5810 ASSERT_EQ(res_stat.allocated, max_object);
5811 g_conf->set_val("bluestore_csum_type", "crc32c");
5812}
5813
5814TEST_P(StoreTestSpecificAUSize, TooManyBlobsTest) {
5815 if (string(GetParam()) != "bluestore")
5816 return;
5817 StartDeferred(0x10000);
5818 store_statfs_t res_stat;
5819 unsigned max_object = 4*1024*1024;
5820 doMany4KWritesTest(store, 1, 1000, max_object, 4*1024, 0, &res_stat);
5821 ASSERT_LE(res_stat.stored, max_object);
5822 ASSERT_EQ(res_stat.allocated, max_object);
5823}
5824
5825#if defined(HAVE_LIBAIO)
5826void get_mempool_stats(uint64_t* total_bytes, uint64_t* total_items)
5827{
31f18b77
FG
5828 uint64_t onode_allocated = mempool::bluestore_cache_onode::allocated_bytes();
5829 uint64_t other_allocated = mempool::bluestore_cache_other::allocated_bytes();
7c673cae 5830
31f18b77
FG
5831 uint64_t onode_items = mempool::bluestore_cache_onode::allocated_items();
5832 uint64_t other_items = mempool::bluestore_cache_other::allocated_items();
7c673cae
FG
5833 cout << "onode(" << onode_allocated << "/" << onode_items
5834 << ") other(" << other_allocated << "/" << other_items
5835 << ")" << std::endl;
5836 *total_bytes = onode_allocated + other_allocated;
5837 *total_items = onode_items;
5838}
5839
5840TEST_P(StoreTestSpecificAUSize, OnodeSizeTracking) {
5841
5842 if (string(GetParam()) != "bluestore")
5843 return;
5844
5845 size_t block_size = 4096;
5846 StartDeferred(block_size);
5847 g_conf->set_val("bluestore_compression_mode", "none");
5848 g_conf->set_val("bluestore_csum_type", "none");
224ce89b
WB
5849 g_conf->set_val("bluestore_cache_size_hdd", "400000000");
5850 g_conf->set_val("bluestore_cache_size_ssd", "400000000");
7c673cae
FG
5851 g_conf->apply_changes(NULL);
5852
5853 ObjectStore::Sequencer osr("test");
5854 int r;
5855 coll_t cid;
5856 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
5857 size_t obj_size = 4 * 1024 * 1024;
5858 uint64_t total_bytes, total_bytes2;
5859 uint64_t total_onodes;
5860 get_mempool_stats(&total_bytes, &total_onodes);
5861 ASSERT_EQ(total_onodes, 0u);
5862
5863 {
5864 ObjectStore::Transaction t;
5865 t.create_collection(cid, 0);
5866 r = apply_transaction(store, &osr, std::move(t));
5867 ASSERT_EQ(r, 0);
5868 }
5869 {
5870 ObjectStore::Transaction t;
5871 bufferlist bl, orig, orig2;
5872
5873 bl.append(std::string(obj_size, 'a'));
5874 t.write(cid, hoid, 0, bl.length(), bl);
5875 r = apply_transaction(store, &osr, std::move(t));
5876 ASSERT_EQ(r, 0);
5877 }
5878 get_mempool_stats(&total_bytes, &total_onodes);
5879 ASSERT_NE(total_bytes, 0u);
5880 ASSERT_EQ(total_onodes, 1u);
5881
5882 {
5883 ObjectStore::Transaction t;
5884 t.truncate(cid, hoid, 0);
5885 r = apply_transaction(store, &osr, std::move(t));
5886 ASSERT_EQ(r, 0);
5887 }
5888
5889 for(size_t i = 0; i < 1; ++i) {
5890 bufferlist bl;
5891 bl.append(std::string(block_size * (i+1), 'a'));
5892 for( size_t j = 0; j < obj_size; j+= bl.length()) {
5893 ObjectStore::Transaction t;
5894 t.write(cid, hoid, j, bl.length(), bl);
5895 r = apply_transaction(store, &osr, std::move(t));
5896 ASSERT_EQ(r, 0);
5897 }
5898 get_mempool_stats(&total_bytes2, &total_onodes);
5899 ASSERT_NE(total_bytes2, 0u);
5900 ASSERT_EQ(total_onodes, 1u);
5901 }
5902 {
5903 cout <<" mempool dump:\n";
5904 JSONFormatter f(true);
5905 f.open_object_section("transaction");
5906 mempool::dump(&f);
5907 f.close_section();
5908 f.flush(cout);
5909 cout << std::endl;
5910 }
5911 {
5912 bufferlist bl;
5913 for (size_t i = 0; i < obj_size; i += 0x1000) {
5914 store->read(cid, hoid, i, 0x1000, bl);
5915 }
5916 }
5917 get_mempool_stats(&total_bytes, &total_onodes);
5918 ASSERT_NE(total_bytes, 0u);
5919 ASSERT_EQ(total_onodes, 1u);
5920
5921 {
5922 cout <<" mempool dump:\n";
5923 JSONFormatter f(true);
5924 f.open_object_section("transaction");
5925 mempool::dump(&f);
5926 f.close_section();
5927 f.flush(cout);
5928 cout << std::endl;
5929 }
5930 {
5931 ObjectStore::Transaction t;
5932 t.remove(cid, hoid);
5933 t.remove_collection(cid);
5934 cerr << "Cleaning" << std::endl;
5935 r = apply_transaction(store, &osr, std::move(t));
5936 ASSERT_EQ(r, 0);
5937 }
224ce89b
WB
5938 g_ceph_context->_conf->set_val("bluestore_cache_size_hdd", "4000000");
5939 g_ceph_context->_conf->set_val("bluestore_cache_size_ssd", "4000000");
7c673cae
FG
5940 g_conf->set_val("bluestore_compression_mode", "none");
5941 g_conf->set_val("bluestore_csum_type", "crc32c");
5942
5943}
5944
5945TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwrite) {
5946
5947 if (string(GetParam()) != "bluestore")
5948 return;
5949
5950 size_t block_size = 4096;
5951 StartDeferred(block_size);
5952 g_conf->set_val("bluestore_max_blob_size", "65536");
5953 g_conf->apply_changes(NULL);
5954
5955 ObjectStore::Sequencer osr("test");
5956 int r;
5957 coll_t cid;
5958 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
5959
5960 const PerfCounters* logger = store->get_perf_counters();
5961
5962 {
5963 ObjectStore::Transaction t;
5964 t.create_collection(cid, 0);
5965 r = apply_transaction(store, &osr, std::move(t));
5966 ASSERT_EQ(r, 0);
5967 }
5968 {
5969 ObjectStore::Transaction t;
5970 bufferlist bl;
5971
5972 bl.append(std::string(block_size * 2, 'a'));
5973 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5974 r = apply_transaction(store, &osr, std::move(t));
5975 ASSERT_EQ(r, 0);
5976 }
5977 {
5978 // overwrite at the beginning
5979 ObjectStore::Transaction t;
5980 bufferlist bl;
5981
5982 bl.append(std::string(block_size, 'b'));
5983 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5984 r = apply_transaction(store, &osr, std::move(t));
5985 ASSERT_EQ(r, 0);
5986 }
5987 {
5988 // append
5989 ObjectStore::Transaction t;
5990 bufferlist bl;
5991
5992 bl.append(std::string(block_size * 2, 'c'));
5993 t.write(cid, hoid, block_size * 2, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
5994 r = apply_transaction(store, &osr, std::move(t));
5995 ASSERT_EQ(r, 0);
5996 }
5997 {
5998 // append with a gap
5999 ObjectStore::Transaction t;
6000 bufferlist bl;
6001
6002 bl.append(std::string(block_size * 2, 'd'));
6003 t.write(cid, hoid, block_size * 5, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6004 r = apply_transaction(store, &osr, std::move(t));
6005 ASSERT_EQ(r, 0);
6006 }
6007 {
6008 // We need to issue a read to trigger cache stat update that refresh
6009 // perf counters. additionally we need to wait some time for mempool
6010 // thread to update stats.
6011 sleep(1);
6012 bufferlist bl, expected;
6013 r = store->read(cid, hoid, 0, block_size, bl);
6014 ASSERT_EQ(r, (int)block_size);
6015 expected.append(string(block_size, 'b'));
6016 ASSERT_TRUE(bl_eq(expected, bl));
6017 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6018 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
6019 }
6020 {
6021 // overwrite at end
6022 ObjectStore::Transaction t;
6023 bufferlist bl;
6024
6025 bl.append(std::string(block_size * 2, 'e'));
6026
6027 // Currently we are unable to reuse blob when overwriting in a single step
6028 t.write(cid, hoid, block_size * 6, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6029 r = apply_transaction(store, &osr, std::move(t));
6030 ASSERT_EQ(r, 0);
6031 }
6032 {
6033 // We need to issue a read to trigger cache stat update that refresh
6034 // perf counters. additionally we need to wait some time for mempool
6035 // thread to update stats.
6036 sleep(1);
6037 bufferlist bl, expected;
6038 r = store->read(cid, hoid, 0, block_size, bl);
6039 ASSERT_EQ(r, (int)block_size);
6040 expected.append(string(block_size, 'b'));
6041 ASSERT_TRUE(bl_eq(expected, bl));
6042 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6043 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
6044 }
6045 {
6046 // fill the gap
6047 ObjectStore::Transaction t;
6048 bufferlist bl;
6049
6050 bl.append(std::string(block_size, 'f'));
6051
6052 t.write(cid, hoid, block_size * 4, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6053 r = apply_transaction(store, &osr, std::move(t));
6054 ASSERT_EQ(r, 0);
6055 }
6056 {
6057 // we need to wait some time for mempool
6058 // thread to update stats to be able to check blob/extent numbers from
6059 // perf counters.
6060 sleep(1);
6061
6062 bufferlist bl, expected;
6063 r = store->read(cid, hoid, 0, block_size, bl);
6064 ASSERT_EQ(r, (int)block_size);
6065 expected.append(string(block_size, 'b'));
6066 ASSERT_TRUE(bl_eq(expected, bl));
6067
6068 bl.clear();
6069 expected.clear();
6070 r = store->read(cid, hoid, block_size, block_size, bl);
6071 ASSERT_EQ(r, (int)block_size);
6072 expected.append(string(block_size, 'a'));
6073 ASSERT_TRUE(bl_eq(expected, bl));
6074
6075 bl.clear();
6076 expected.clear();
6077 r = store->read(cid, hoid, block_size * 2, block_size * 2, bl);
6078 ASSERT_EQ(r, (int)block_size * 2);
6079 expected.append(string(block_size * 2, 'c'));
6080 ASSERT_TRUE(bl_eq(expected, bl));
6081
6082 bl.clear();
6083 expected.clear();
6084 r = store->read(cid, hoid, block_size * 4, block_size, bl);
6085 ASSERT_EQ(r, (int)block_size);
6086 expected.append(string(block_size, 'f'));
6087 ASSERT_TRUE(bl_eq(expected, bl));
6088
6089 bl.clear();
6090 expected.clear();
6091 r = store->read(cid, hoid, block_size * 5, block_size, bl);
6092 ASSERT_EQ(r, (int)block_size);
6093 expected.append(string(block_size, 'd'));
6094 ASSERT_TRUE(bl_eq(expected, bl));
6095
6096 bl.clear();
6097 expected.clear();
6098 r = store->read(cid, hoid, block_size * 5, block_size * 3, bl);
6099 ASSERT_EQ(r, (int)block_size * 3);
6100 expected.append(string(block_size, 'd'));
6101 expected.append(string(block_size * 2, 'e'));
6102 ASSERT_TRUE(bl_eq(expected, bl));
6103 }
6104 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6105 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
6106
6107
6108 {
6109 ObjectStore::Transaction t;
6110 t.remove(cid, hoid);
6111 t.remove_collection(cid);
6112 cerr << "Cleaning" << std::endl;
6113 r = apply_transaction(store, &osr, std::move(t));
6114 ASSERT_EQ(r, 0);
6115 }
6116 g_conf->set_val("bluestore_max_blob_size", "0");
6117
6118}
6119
6120TEST_P(StoreTestSpecificAUSize, BlobReuseOnOverwriteReverse) {
6121
6122 if (string(GetParam()) != "bluestore")
6123 return;
6124
6125 size_t block_size = 4096;
6126 StartDeferred(block_size);
6127 g_conf->set_val("bluestore_max_blob_size", "65536");
6128
6129 g_conf->apply_changes(NULL);
6130
6131 ObjectStore::Sequencer osr("test");
6132 int r;
6133 coll_t cid;
6134 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6135
6136 const PerfCounters* logger = store->get_perf_counters();
6137 {
6138 ObjectStore::Transaction t;
6139 t.create_collection(cid, 0);
6140 r = apply_transaction(store, &osr, std::move(t));
6141 ASSERT_EQ(r, 0);
6142 }
6143 {
6144 ObjectStore::Transaction t;
6145 bufferlist bl;
6146
6147 bl.append(std::string(block_size * 2, 'a'));
6148 t.write(cid, hoid, block_size * 10, bl.length(), bl,
6149 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6150 r = apply_transaction(store, &osr, std::move(t));
6151 ASSERT_EQ(r, 0);
6152 }
6153 {
6154 // prepend existing
6155 ObjectStore::Transaction t;
6156 bufferlist bl;
6157
6158 bl.append(std::string(block_size, 'b'));
6159 t.write(cid, hoid, block_size * 9, bl.length(), bl,
6160 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6161 r = apply_transaction(store, &osr, std::move(t));
6162 ASSERT_EQ(r, 0);
6163 }
6164 {
6165 // We need to issue a read to trigger cache stat update that refresh
6166 // perf counters. additionally we need to wait some time for mempool
6167 // thread to update stats.
6168 sleep(1);
6169 bufferlist bl, expected;
6170 r = store->read(cid, hoid, block_size * 9, block_size * 2, bl);
6171 ASSERT_EQ(r, (int)block_size * 2);
6172 expected.append(string(block_size, 'b'));
6173 expected.append(string(block_size, 'a'));
6174 ASSERT_TRUE(bl_eq(expected, bl));
6175 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6176 ASSERT_EQ(logger->get(l_bluestore_extents), 1u);
6177 }
6178
6179
6180 {
6181 // prepend existing with a gap
6182 ObjectStore::Transaction t;
6183 bufferlist bl;
6184
6185 bl.append(std::string(block_size, 'c'));
6186 t.write(cid, hoid, block_size * 7, bl.length(), bl,
6187 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6188 r = apply_transaction(store, &osr, std::move(t));
6189 ASSERT_EQ(r, 0);
6190 }
6191 {
6192 // We need to issue a read to trigger cache stat update that refresh
6193 // perf counters. additionally we need to wait some time for mempool
6194 // thread to update stats.
6195 sleep(1);
6196 bufferlist bl, expected;
6197 r = store->read(cid, hoid, block_size * 7, block_size * 3, bl);
6198 ASSERT_EQ(r, (int)block_size * 3);
6199 expected.append(string(block_size, 'c'));
6200 expected.append(string(block_size, 0));
6201 expected.append(string(block_size, 'b'));
6202 ASSERT_TRUE(bl_eq(expected, bl));
6203 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6204 ASSERT_EQ(logger->get(l_bluestore_extents), 2u);
6205 }
6206
6207 {
6208 // append after existing with a gap
6209 ObjectStore::Transaction t;
6210 bufferlist bl;
6211
6212 bl.append(std::string(block_size, 'd'));
6213 t.write(cid, hoid, block_size * 13, bl.length(), bl,
6214 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6215 r = apply_transaction(store, &osr, std::move(t));
6216 ASSERT_EQ(r, 0);
6217 }
6218 {
6219 // We need to issue a read to trigger cache stat update that refresh
6220 // perf counters. additionally we need to wait some time for mempool
6221 // thread to update stats.
6222 sleep(1);
6223 bufferlist bl, expected;
6224 r = store->read(cid, hoid, block_size * 11, block_size * 3, bl);
6225 ASSERT_EQ(r, (int)block_size * 3);
6226 expected.append(string(block_size, 'a'));
6227 expected.append(string(block_size, 0));
6228 expected.append(string(block_size, 'd'));
6229 ASSERT_TRUE(bl_eq(expected, bl));
6230 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6231 ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
6232 }
6233
6234 {
6235 // append twice to the next max_blob slot
6236 ObjectStore::Transaction t;
6237 bufferlist bl;
6238
6239 bl.append(std::string(block_size, 'e'));
6240 t.write(cid, hoid, block_size * 17, bl.length(), bl,
6241 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6242 t.write(cid, hoid, block_size * 19, bl.length(), bl,
6243 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6244 r = apply_transaction(store, &osr, std::move(t));
6245 ASSERT_EQ(r, 0);
6246 }
6247 {
6248 // We need to issue a read to trigger cache stat update that refresh
6249 // perf counters. additionally we need to wait some time for mempool
6250 // thread to update stats.
6251 sleep(1);
6252 bufferlist bl, expected;
6253 r = store->read(cid, hoid, block_size * 17, block_size * 3, bl);
6254 ASSERT_EQ(r, (int)block_size * 3);
6255 expected.append(string(block_size, 'e'));
6256 expected.append(string(block_size, 0));
6257 expected.append(string(block_size, 'e'));
6258 ASSERT_TRUE(bl_eq(expected, bl));
6259 ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
6260 ASSERT_EQ(logger->get(l_bluestore_extents), 5u);
6261 }
6262 {
6263 // fill gaps at the second slot
6264 ObjectStore::Transaction t;
6265 bufferlist bl;
6266
6267 bl.append(std::string(block_size, 'f'));
6268 t.write(cid, hoid, block_size * 16, bl.length(), bl,
6269 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6270 t.write(cid, hoid, block_size * 18, bl.length(), bl,
6271 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6272 r = apply_transaction(store, &osr, std::move(t));
6273 ASSERT_EQ(r, 0);
6274 }
6275 {
6276 // We need to issue a read to trigger cache stat update that refresh
6277 // perf counters. additionally we need to wait some time for mempool
6278 // thread to update stats.
6279 sleep(1);
6280 bufferlist bl, expected;
6281 r = store->read(cid, hoid, block_size * 16, block_size * 4, bl);
6282 ASSERT_EQ(r, (int)block_size * 4);
6283 expected.append(string(block_size, 'f'));
6284 expected.append(string(block_size, 'e'));
6285 expected.append(string(block_size, 'f'));
6286 expected.append(string(block_size, 'e'));
6287 ASSERT_TRUE(bl_eq(expected, bl));
6288 ASSERT_EQ(logger->get(l_bluestore_blobs), 2u);
6289 ASSERT_EQ(logger->get(l_bluestore_extents), 4u);
6290 }
6291 {
6292 ObjectStore::Transaction t;
6293 t.remove(cid, hoid);
6294 t.remove_collection(cid);
6295 cerr << "Cleaning" << std::endl;
6296 r = apply_transaction(store, &osr, std::move(t));
6297 ASSERT_EQ(r, 0);
6298 }
6299 g_conf->set_val("bluestore_max_blob_size", "0");
6300}
6301
6302TEST_P(StoreTestSpecificAUSize, BlobReuseOnSmallOverwrite) {
6303
6304 if (string(GetParam()) != "bluestore")
6305 return;
6306
6307 size_t block_size = 4096;
6308 StartDeferred(block_size);
6309 g_conf->set_val("bluestore_max_blob_size", "65536");
6310 g_conf->apply_changes(NULL);
6311
6312 ObjectStore::Sequencer osr("test");
6313 int r;
6314 coll_t cid;
6315 ghobject_t hoid(hobject_t("test_hint", "", CEPH_NOSNAP, 0, -1, ""));
6316
6317 const PerfCounters* logger = store->get_perf_counters();
6318
6319 {
6320 ObjectStore::Transaction t;
6321 t.create_collection(cid, 0);
6322 r = apply_transaction(store, &osr, std::move(t));
6323 ASSERT_EQ(r, 0);
6324 }
6325 {
6326 ObjectStore::Transaction t;
6327 bufferlist bl;
6328
6329 bl.append(std::string(block_size, 'a'));
6330 t.write(cid, hoid, 0, bl.length(), bl, CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6331 t.write(cid, hoid, block_size * 2, bl.length(), bl,
6332 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6333 r = apply_transaction(store, &osr, std::move(t));
6334 ASSERT_EQ(r, 0);
6335 }
6336 {
6337 // write small into the gap
6338 ObjectStore::Transaction t;
6339 bufferlist bl;
6340
6341 bl.append(std::string(3, 'b'));
6342 t.write(cid, hoid, block_size + 1, bl.length(), bl,
6343 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
6344 r = apply_transaction(store, &osr, std::move(t));
6345 ASSERT_EQ(r, 0);
6346 }
6347 {
6348 // We need to issue a read to trigger cache stat update that refresh
6349 // perf counters. additionally we need to wait some time for mempool
6350 // thread to update stats.
6351 sleep(1);
6352 bufferlist bl, expected;
6353 r = store->read(cid, hoid, 0, block_size * 3, bl);
6354 ASSERT_EQ(r, (int)block_size * 3);
6355 expected.append(string(block_size, 'a'));
6356 expected.append(string(1, 0));
6357 expected.append(string(3, 'b'));
6358 expected.append(string(block_size - 4, 0));
6359 expected.append(string(block_size, 'a'));
6360 ASSERT_TRUE(bl_eq(expected, bl));
6361
6362 ASSERT_EQ(logger->get(l_bluestore_blobs), 1u);
6363 ASSERT_EQ(logger->get(l_bluestore_extents), 3u);
6364 }
6365 {
6366 ObjectStore::Transaction t;
6367 t.remove(cid, hoid);
6368 t.remove_collection(cid);
6369 cerr << "Cleaning" << std::endl;
6370 r = apply_transaction(store, &osr, std::move(t));
6371 ASSERT_EQ(r, 0);
6372 }
6373 g_conf->set_val("bluestore_max_blob_size", "0");
6374}
6375
6376// The test case to reproduce an issue when write happens
6377// to a zero space between the extents sharing the same spanning blob
6378// with unloaded shard map.
6379// Second extent might be filled with zeros this way due to wrong result
6380// returned by has_any_extents() call in do_write_small. The latter is caused
6381// by incompletly loaded extent map.
6382TEST_P(StoreTestSpecificAUSize, SmallWriteOnShardedExtents) {
6383 if (string(GetParam()) != "bluestore")
6384 return;
6385
6386 size_t block_size = 0x10000;
6387 StartDeferred(block_size);
6388
6389 g_conf->set_val("bluestore_csum_type", "xxhash64");
6390 g_conf->set_val("bluestore_max_target_blob", "524288"); // for sure
6391
6392 g_conf->apply_changes(NULL);
6393
6394 ObjectStore::Sequencer osr("test");
6395 int r;
6396 coll_t cid;
6397 ghobject_t hoid1(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
6398
6399 {
6400 ObjectStore::Transaction t;
6401 t.create_collection(cid, 0);
6402 r = apply_transaction(store, &osr, std::move(t));
6403 ASSERT_EQ(r, 0);
6404 }
6405 {
6406 //doing some tricks to have sharded extents/spanning objects
6407 ObjectStore::Transaction t;
6408 bufferlist bl, bl2;
6409
6410 bl.append(std::string(0x80000, 'a'));
6411 t.write(cid, hoid1, 0, bl.length(), bl, 0);
6412 t.zero(cid, hoid1, 0x719e0, 0x75b0 );
6413 r = apply_transaction(store, &osr, std::move(t));
6414 ASSERT_EQ(r, 0);
6415
6416 bl2.append(std::string(0x70000, 'b'));
6417 t.write(cid, hoid1, 0, bl2.length(), bl2, 0);
6418 t.zero(cid, hoid1, 0, 0x50000);
6419 r = apply_transaction(store, &osr, std::move(t));
31f18b77 6420 ASSERT_EQ(r, 0);
7c673cae
FG
6421
6422 }
6423 store->umount();
6424 store->mount();
6425
6426 {
6427 // do a write to zero space in between some extents sharing the same blob
6428 ObjectStore::Transaction t;
6429 bufferlist bl, bl2;
6430
6431 bl.append(std::string(0x6520, 'c'));
6432 t.write(cid, hoid1, 0x71c00, bl.length(), bl, 0);
6433
6434 r = apply_transaction(store, &osr, std::move(t));
6435 ASSERT_EQ(r, 0);
6436 }
6437
6438 {
6439 ObjectStore::Transaction t;
6440 bufferlist bl, expected;
6441
6442 r = store->read(cid, hoid1, 0x70000, 0x9c00, bl);
6443 ASSERT_EQ(r, (int)0x9c00);
6444 expected.append(string(0x19e0, 'a'));
6445 expected.append(string(0x220, 0));
6446 expected.append(string(0x6520, 'c'));
6447 expected.append(string(0xe70, 0));
6448 expected.append(string(0xc70, 'a'));
6449 ASSERT_TRUE(bl_eq(expected, bl));
6450 bl.clear();
6451
6452 }
6453
6454 {
6455 ObjectStore::Transaction t;
6456 t.remove(cid, hoid1);
6457 t.remove_collection(cid);
6458 cerr << "Cleaning" << std::endl;
6459 r = apply_transaction(store, &osr, std::move(t));
6460 ASSERT_EQ(r, 0);
6461 }
6462 g_conf->set_val("bluestore_max_target_blob", "524288");
6463 g_conf->set_val("bluestore_csum_type", "crc32c");
6464}
6465
6466#endif //#if defined(HAVE_LIBAIO)
6467
6468TEST_P(StoreTest, KVDBHistogramTest) {
6469 if (string(GetParam()) != "bluestore")
6470 return;
6471
6472 ObjectStore::Sequencer osr("test");
6473 int NUM_OBJS = 200;
6474 int r = 0;
6475 coll_t cid;
6476 string base("testobj.");
6477 bufferlist a;
6478 bufferptr ap(0x1000);
6479 memset(ap.c_str(), 'a', 0x1000);
6480 a.append(ap);
6481 {
6482 ObjectStore::Transaction t;
6483 t.create_collection(cid, 0);
6484 r = apply_transaction(store, &osr, std::move(t));
6485 ASSERT_EQ(r, 0);
6486 }
6487 for (int i = 0; i < NUM_OBJS; ++i) {
6488 ObjectStore::Transaction t;
6489 char buf[100];
6490 snprintf(buf, sizeof(buf), "%d", i);
6491 ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
6492 t.write(cid, hoid, 0, 0x1000, a);
6493 r = apply_transaction(store, &osr, std::move(t));
6494 ASSERT_EQ(r, 0);
6495 }
6496
6497 Formatter *f = Formatter::create("store_test", "json-pretty", "json-pretty");
6498 store->generate_db_histogram(f);
6499 f->flush(cout);
6500 cout << std::endl;
6501}
6502
6503TEST_P(StoreTest, KVDBStatsTest) {
6504 if (string(GetParam()) != "bluestore")
6505 return;
6506
6507 g_conf->set_val("rocksdb_perf", "true");
6508 g_conf->set_val("rocksdb_collect_compaction_stats", "true");
6509 g_conf->set_val("rocksdb_collect_extended_stats","true");
6510 g_conf->set_val("rocksdb_collect_memory_stats","true");
6511 g_ceph_context->_conf->apply_changes(NULL);
6512 int r = store->umount();
6513 ASSERT_EQ(r, 0);
6514 r = store->mount(); //to force rocksdb stats
6515 ASSERT_EQ(r, 0);
6516
6517 ObjectStore::Sequencer osr("test");
6518 int NUM_OBJS = 200;
6519 coll_t cid;
6520 string base("testobj.");
6521 bufferlist a;
6522 bufferptr ap(0x1000);
6523 memset(ap.c_str(), 'a', 0x1000);
6524 a.append(ap);
6525 {
6526 ObjectStore::Transaction t;
6527 t.create_collection(cid, 0);
6528 r = apply_transaction(store, &osr, std::move(t));
6529 ASSERT_EQ(r, 0);
6530 }
6531 for (int i = 0; i < NUM_OBJS; ++i) {
6532 ObjectStore::Transaction t;
6533 char buf[100];
6534 snprintf(buf, sizeof(buf), "%d", i);
6535 ghobject_t hoid(hobject_t(sobject_t(base + string(buf), CEPH_NOSNAP)));
6536 t.write(cid, hoid, 0, 0x1000, a);
6537 r = apply_transaction(store, &osr, std::move(t));
6538 ASSERT_EQ(r, 0);
6539 }
6540
6541 Formatter *f = Formatter::create("store_test", "json-pretty", "json-pretty");
6542 store->get_db_statistics(f);
6543 f->flush(cout);
6544 cout << std::endl;
6545 g_conf->set_val("rocksdb_perf", "false");
6546 g_conf->set_val("rocksdb_collect_compaction_stats", "false");
6547 g_conf->set_val("rocksdb_collect_extended_stats","false");
6548 g_conf->set_val("rocksdb_collect_memory_stats","false");
6549}
6550
6551#if defined(HAVE_LIBAIO)
6552TEST_P(StoreTestSpecificAUSize, garbageCollection) {
6553 ObjectStore::Sequencer osr("test");
6554 int r;
6555 coll_t cid;
6556 int buf_len = 256 * 1024;
6557 int overlap_offset = 64 * 1024;
6558 int write_offset = buf_len;
6559 if (string(GetParam()) != "bluestore")
6560 return;
6561
6562#define WRITE_AT(offset, _length) {\
6563 ObjectStore::Transaction t;\
6564 if ((uint64_t)_length != bl.length()) { \
6565 buffer::ptr p(bl.c_str(), _length);\
6566 bufferlist bl_tmp;\
6567 bl_tmp.push_back(p);\
6568 t.write(cid, hoid, offset, bl_tmp.length(), bl_tmp);\
6569 } else {\
6570 t.write(cid, hoid, offset, bl.length(), bl);\
6571 }\
6572 r = apply_transaction(store, &osr, std::move(t));\
6573 ASSERT_EQ(r, 0);\
6574 }
6575
6576 StartDeferred(65536);
6577
6578 g_conf->set_val("bluestore_compression_max_blob_size", "524288");
6579 g_conf->set_val("bluestore_compression_min_blob_size", "262144");
6580 g_conf->set_val("bluestore_compression_mode", "force");
6581 g_conf->apply_changes(NULL);
6582
6583 ghobject_t hoid(hobject_t(sobject_t("Object 1", CEPH_NOSNAP)));
6584 {
6585 bufferlist in;
6586 r = store->read(cid, hoid, 0, 5, in);
6587 ASSERT_EQ(-ENOENT, r);
6588 }
6589 {
6590 ObjectStore::Transaction t;
6591 t.create_collection(cid, 0);
6592 cerr << "Creating collection " << cid << std::endl;
6593 r = apply_transaction(store, &osr, std::move(t));
6594 ASSERT_EQ(r, 0);
6595 }
6596
6597 std::string data;
6598 data.resize(buf_len);
6599
6600 {
6601 {
6602 bool exists = store->exists(cid, hoid);
6603 ASSERT_TRUE(!exists);
6604
6605 ObjectStore::Transaction t;
6606 t.touch(cid, hoid);
6607 cerr << "Creating object " << hoid << std::endl;
6608 r = apply_transaction(store, &osr, std::move(t));
6609 ASSERT_EQ(r, 0);
6610
6611 exists = store->exists(cid, hoid);
6612 ASSERT_EQ(true, exists);
6613 }
6614 bufferlist bl;
6615
6616 for(size_t i = 0; i < data.size(); i++)
6617 data[i] = i % 256;
6618
6619 bl.append(data);
6620
6621 {
6622 struct store_statfs_t statfs;
6623 WRITE_AT(0, buf_len);
6624 int r = store->statfs(&statfs);
6625 ASSERT_EQ(r, 0);
6626 ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6627 }
6628 {
6629 struct store_statfs_t statfs;
6630 WRITE_AT(write_offset - 2 * overlap_offset, buf_len);
6631 int r = store->statfs(&statfs);
6632 ASSERT_EQ(r, 0);
6633 ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6634 const PerfCounters* counters = store->get_perf_counters();
6635 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0u);
6636 }
6637
6638 {
6639 struct store_statfs_t statfs;
6640 WRITE_AT(write_offset - overlap_offset, buf_len);
6641 int r = store->statfs(&statfs);
6642 ASSERT_EQ(r, 0);
6643 ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6644 const PerfCounters* counters = store->get_perf_counters();
6645 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x10000u);
6646 }
6647 {
6648 struct store_statfs_t statfs;
6649 WRITE_AT(write_offset - 3 * overlap_offset, buf_len);
6650 int r = store->statfs(&statfs);
6651 ASSERT_EQ(r, 0);
6652 ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6653 const PerfCounters* counters = store->get_perf_counters();
6654 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
6655 }
6656 {
6657 struct store_statfs_t statfs;
6658 WRITE_AT(write_offset + 1, overlap_offset-1);
6659 int r = store->statfs(&statfs);
6660 ASSERT_EQ(r, 0);
6661 ASSERT_EQ(statfs.compressed_allocated, 0x20000);
6662 const PerfCounters* counters = store->get_perf_counters();
6663 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x20000u);
6664 }
6665 {
6666 struct store_statfs_t statfs;
6667 WRITE_AT(write_offset + 1, overlap_offset);
6668 int r = store->statfs(&statfs);
6669 ASSERT_EQ(r, 0);
6670 ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6671 const PerfCounters* counters = store->get_perf_counters();
6672 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x3ffffu);
6673 }
6674 {
6675 struct store_statfs_t statfs;
6676 WRITE_AT(0, buf_len-1);
6677 int r = store->statfs(&statfs);
6678 ASSERT_EQ(r, 0);
6679 ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6680 const PerfCounters* counters = store->get_perf_counters();
6681 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
6682 }
6683 g_conf->set_val("bluestore_gc_enable_total_threshold", "1"); //forbid GC when saving = 0
6684 {
6685 struct store_statfs_t statfs;
6686 WRITE_AT(1, overlap_offset-2);
6687 WRITE_AT(overlap_offset * 2 + 1, overlap_offset-2);
6688 int r = store->statfs(&statfs);
6689 ASSERT_EQ(r, 0);
6690 ASSERT_EQ(statfs.compressed_allocated, 0x10000);
6691 const PerfCounters* counters = store->get_perf_counters();
6692 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40001u);
6693 }
6694 {
6695 struct store_statfs_t statfs;
6696 WRITE_AT(overlap_offset + 1, overlap_offset-2);
6697 int r = store->statfs(&statfs);
6698 ASSERT_EQ(r, 0);
6699 ASSERT_EQ(statfs.compressed_allocated, 0x0);
6700 const PerfCounters* counters = store->get_perf_counters();
6701 ASSERT_EQ(counters->get(l_bluestore_gc_merged), 0x40007u);
6702 }
6703 {
6704 ObjectStore::Transaction t;
6705 t.remove(cid, hoid);
6706 cerr << "Cleaning" << std::endl;
6707 r = apply_transaction(store, &osr, std::move(t));
6708 ASSERT_EQ(r, 0);
6709 }
6710 }
6711 g_conf->set_val("bluestore_gc_enable_total_threshold", "0");
6712 g_conf->set_val("bluestore_compression_min_blob_size", "0");
6713 g_conf->set_val("bluestore_compression_max_blob_size", "0");
6714 g_conf->set_val("bluestore_compression_mode", "none");
6715 g_conf->apply_changes(NULL);
6716}
6717#endif
6718
b32b8144
FG
6719TEST_P(StoreTestSpecificAUSize, fsckOnUnalignedDevice) {
6720 if (string(GetParam()) != "bluestore")
6721 return;
6722
6723 g_conf->set_val("bluestore_block_size", stringify(0x280005000)); //10 Gb + 4K
6724 g_conf->set_val("bluestore_fsck_on_mount", "false");
6725 g_conf->set_val("bluestore_fsck_on_umount", "false");
6726 StartDeferred(0x4000);
6727 store->umount();
6728 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
6729 store->mount();
6730
6731 g_conf->set_val("bluestore_fsck_on_mount", "true");
6732 g_conf->set_val("bluestore_fsck_on_umount", "true");
6733 g_conf->set_val("bluestore_block_size", stringify(0x280000000)); // 10 Gb
6734 g_conf->apply_changes(NULL);
6735}
6736
6737TEST_P(StoreTestSpecificAUSize, fsckOnUnalignedDevice2) {
6738 if (string(GetParam()) != "bluestore")
6739 return;
6740
6741 g_conf->set_val("bluestore_block_size", stringify(0x280005000)); //10 Gb + 20K
6742 g_conf->set_val("bluestore_fsck_on_mount", "false");
6743 g_conf->set_val("bluestore_fsck_on_umount", "false");
6744 StartDeferred(0x1000);
6745 store->umount();
6746 ASSERT_EQ(store->fsck(false), 0); // do fsck explicitly
6747 store->mount();
6748
6749 g_conf->set_val("bluestore_block_size", stringify(0x280000000)); // 10 Gb
6750 g_conf->set_val("bluestore_fsck_on_mount", "true");
6751 g_conf->set_val("bluestore_fsck_on_umount", "true");
6752 g_conf->apply_changes(NULL);
6753}
6754
7c673cae
FG
6755int main(int argc, char **argv) {
6756 vector<const char*> args;
6757 argv_to_vec(argc, (const char **)argv, args);
6758 env_to_vec(args);
6759
6760 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
6761 CODE_ENVIRONMENT_UTILITY, 0);
6762 common_init_finish(g_ceph_context);
6763
6764 g_ceph_context->_conf->set_val("osd_journal_size", "400");
6765 g_ceph_context->_conf->set_val("filestore_index_retry_probability", "0.5");
6766 g_ceph_context->_conf->set_val("filestore_op_thread_timeout", "1000");
6767 g_ceph_context->_conf->set_val("filestore_op_thread_suicide_timeout", "10000");
6768 //g_ceph_context->_conf->set_val("filestore_fiemap", "true");
6769 g_ceph_context->_conf->set_val("bluestore_fsck_on_mount", "true");
6770 g_ceph_context->_conf->set_val("bluestore_fsck_on_umount", "true");
6771 g_ceph_context->_conf->set_val("bluestore_debug_misc", "true");
6772 g_ceph_context->_conf->set_val("bluestore_debug_small_allocations", "4");
6773 g_ceph_context->_conf->set_val("bluestore_debug_freelist", "true");
6774 g_ceph_context->_conf->set_val("bluestore_clone_cow", "true");
6775 g_ceph_context->_conf->set_val("bluestore_max_alloc_size", "196608");
6776
6777 // set small cache sizes so we see trimming during Synthetic tests
224ce89b
WB
6778 g_ceph_context->_conf->set_val("bluestore_cache_size_hdd", "4000000");
6779 g_ceph_context->_conf->set_val("bluestore_cache_size_ssd", "4000000");
7c673cae
FG
6780
6781 // very short *_max prealloc so that we fall back to async submits
6782 g_ceph_context->_conf->set_val("bluestore_blobid_prealloc", "10");
6783 g_ceph_context->_conf->set_val("bluestore_nid_prealloc", "10");
6784 g_ceph_context->_conf->set_val("bluestore_debug_randomize_serial_transaction",
6785 "10");
6786
6787 g_ceph_context->_conf->set_val("bdev_debug_aio", "true");
6788
6789 // specify device size
6790 g_ceph_context->_conf->set_val("bluestore_block_size", "10240000000");
6791
6792 g_ceph_context->_conf->set_val(
6793 "enable_experimental_unrecoverable_data_corrupting_features", "*");
6794 g_ceph_context->_conf->apply_changes(NULL);
6795
6796 ::testing::InitGoogleTest(&argc, argv);
6797 return RUN_ALL_TESTS();
6798}
6799
6800/*
6801 * Local Variables:
6802 * compile-command: "cd ../.. ; make ceph_test_objectstore &&
6803 * ./ceph_test_objectstore \
6804 * --gtest_filter=*.collect_metadata* --log-to-stderr=true --debug-filestore=20
6805 * "
6806 * End:
6807 */