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