]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/osd/TestRados.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / osd / TestRados.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
7c673cae
FG
3#include "common/Cond.h"
4#include "common/errno.h"
5#include "common/version.h"
6
7#include <iostream>
8#include <sstream>
9#include <map>
10#include <numeric>
11#include <string>
12#include <vector>
13#include <stdlib.h>
14#include <unistd.h>
15
16#include "test/osd/RadosModel.h"
17
7c673cae
FG
18using namespace std;
19
20class WeightedTestGenerator : public TestOpGenerator
21{
22public:
23
24 WeightedTestGenerator(int ops,
25 int objects,
26 map<TestOpType, unsigned int> op_weights,
27 TestOpStat *stats,
28 int max_seconds,
29 bool ec_pool,
31f18b77 30 bool balance_reads,
9f95a23c 31 bool localize_reads,
11fdf7f2 32 bool set_redirect,
9f95a23c
TL
33 bool set_chunk,
34 bool enable_dedup) :
7c673cae
FG
35 m_nextop(NULL), m_op(0), m_ops(ops), m_seconds(max_seconds),
36 m_objects(objects), m_stats(stats),
37 m_total_weight(0),
38 m_ec_pool(ec_pool),
31f18b77 39 m_balance_reads(balance_reads),
9f95a23c 40 m_localize_reads(localize_reads),
11fdf7f2 41 m_set_redirect(set_redirect),
9f95a23c
TL
42 m_set_chunk(set_chunk),
43 m_enable_dedup(enable_dedup)
7c673cae
FG
44 {
45 m_start = time(0);
46 for (map<TestOpType, unsigned int>::const_iterator it = op_weights.begin();
47 it != op_weights.end();
48 ++it) {
49 m_total_weight += it->second;
50 m_weight_sums.insert(pair<TestOpType, unsigned int>(it->first,
51 m_total_weight));
52 }
11fdf7f2
TL
53 if (m_set_redirect || m_set_chunk) {
54 if (m_set_redirect) {
55 m_ops = ops+m_objects+m_objects;
56 } else {
57 /* create 10 chunks per an object*/
58 m_ops = ops+m_objects+m_objects*10;
59 }
31f18b77 60 }
7c673cae
FG
61 }
62
63 TestOp *next(RadosTestContext &context) override
64 {
65 TestOp *retval = NULL;
66
67 ++m_op;
11fdf7f2 68 if (m_op <= m_objects && !m_set_redirect && !m_set_chunk ) {
7c673cae
FG
69 stringstream oid;
70 oid << m_op;
9f95a23c 71 /*if (m_op % 2) {
7c673cae
FG
72 // make it a long name
73 oid << " " << string(300, 'o');
9f95a23c 74 }*/
7c673cae
FG
75 cout << m_op << ": write initial oid " << oid.str() << std::endl;
76 context.oid_not_flushing.insert(oid.str());
77 if (m_ec_pool) {
78 return new WriteOp(m_op, &context, oid.str(), true, true);
79 } else {
80 return new WriteOp(m_op, &context, oid.str(), false, true);
81 }
82 } else if (m_op >= m_ops) {
83 return NULL;
84 }
31f18b77 85
11fdf7f2
TL
86 if (m_set_redirect || m_set_chunk) {
87 if (init_extensible_tier(context, retval)) {
88 return retval;
31f18b77 89 }
11fdf7f2 90 }
7c673cae
FG
91
92 if (m_nextop) {
93 retval = m_nextop;
94 m_nextop = NULL;
95 return retval;
96 }
97
98 while (retval == NULL) {
99 unsigned int rand_val = rand() % m_total_weight;
100
101 time_t now = time(0);
102 if (m_seconds && now - m_start > m_seconds)
103 break;
104
105 for (map<TestOpType, unsigned int>::const_iterator it = m_weight_sums.begin();
106 it != m_weight_sums.end();
107 ++it) {
108 if (rand_val < it->second) {
109 retval = gen_op(context, it->first);
110 break;
111 }
112 }
113 }
114 return retval;
115 }
116
11fdf7f2
TL
117 bool init_extensible_tier(RadosTestContext &context, TestOp *& op) {
118 /*
119 * set-redirect or set-chunk test (manifest test)
120 * 0. make default objects (using create op)
121 * 1. set-redirect or set-chunk
122 * 2. initialize target objects (using write op)
123 * 3. wait for set-* completion
124 */
125 int copy_manifest_end = 0;
126 if (m_set_chunk) {
127 copy_manifest_end = m_objects*2;
128 } else {
129 copy_manifest_end = m_objects*3;
130 }
131 int make_manifest_end = copy_manifest_end;
132 if (m_set_chunk) {
133 /* make 10 chunks per an object*/
134 make_manifest_end = make_manifest_end + m_objects * 10;
135 } else {
136 /* redirect */
137 make_manifest_end = make_manifest_end + m_objects;
138 }
139
140 if (m_op <= m_objects) {
141 stringstream oid;
142 oid << m_op;
9f95a23c 143 /*if (m_op % 2) {
11fdf7f2 144 oid << " " << string(300, 'o');
9f95a23c 145 }*/
11fdf7f2
TL
146 cout << m_op << ": write initial oid " << oid.str() << std::endl;
147 context.oid_not_flushing.insert(oid.str());
148 if (m_ec_pool) {
149 op = new WriteOp(m_op, &context, oid.str(), true, true);
150 } else {
151 op = new WriteOp(m_op, &context, oid.str(), false, true);
152 }
153 return true;
154 } else if (m_op <= copy_manifest_end) {
155 stringstream oid, oid2;
156 //int _oid = m_op-m_objects;
157 int _oid = m_op % m_objects + 1;
158 oid << _oid;
9f95a23c 159 /*if ((_oid) % 2) {
11fdf7f2 160 oid << " " << string(300, 'o');
9f95a23c
TL
161 }*/
162
163 if (context.oid_in_use.count(oid.str())) {
164 /* previous write is not finished */
165 op = NULL;
166 m_op--;
167 cout << m_op << " wait for completion of write op! " << std::endl;
168 return true;
169 }
170
11fdf7f2
TL
171 int _oid2 = m_op - m_objects + 1;
172 if (_oid2 > copy_manifest_end - m_objects) {
173 _oid2 -= (copy_manifest_end - m_objects);
174 }
175 oid2 << _oid2 << " " << context.low_tier_pool_name;
176 if ((_oid2) % 2) {
177 oid2 << " " << string(300, 'm');
178 }
179 cout << m_op << ": " << "copy oid " << oid.str() << " target oid "
180 << oid2.str() << std::endl;
181 op = new CopyOp(m_op, &context, oid.str(), oid2.str(), context.low_tier_pool_name);
182 return true;
183 } else if (m_op <= make_manifest_end) {
184 if (m_set_redirect) {
185 stringstream oid, oid2;
186 int _oid = m_op-copy_manifest_end;
187 oid << _oid;
9f95a23c 188 /*if ((_oid) % 2) {
11fdf7f2 189 oid << " " << string(300, 'o');
9f95a23c 190 }*/
11fdf7f2
TL
191 oid2 << _oid << " " << context.low_tier_pool_name;
192 if ((_oid) % 2) {
193 oid2 << " " << string(300, 'm');
194 }
195 if (context.oid_in_use.count(oid.str())) {
196 /* previous copy is not finished */
197 op = NULL;
198 m_op--;
199 cout << m_op << " retry set_redirect !" << std::endl;
200 return true;
201 }
202 cout << m_op << ": " << "set_redirect oid " << oid.str() << " target oid "
203 << oid2.str() << std::endl;
204 op = new SetRedirectOp(m_op, &context, oid.str(), oid2.str(), context.pool_name);
205 return true;
206 } else if (m_set_chunk) {
207 stringstream oid;
208 int _oid = m_op % m_objects +1;
209 oid << _oid;
9f95a23c 210 /*if ((_oid) % 2) {
11fdf7f2 211 oid << " " << string(300, 'o');
9f95a23c 212 }*/
11fdf7f2
TL
213 if (context.oid_in_use.count(oid.str())) {
214 /* previous set-chunk is not finished */
215 op = NULL;
216 m_op--;
217 cout << m_op << " retry set_chunk !" << std::endl;
218 return true;
219 }
220 stringstream oid2;
221 oid2 << _oid << " " << context.low_tier_pool_name;
222 if ((_oid) % 2) {
223 oid2 << " " << string(300, 'm');
224 }
225
20effc67
TL
226 cout << m_op << ": " << "set_chunk oid " << oid.str()
227 << " target oid " << oid2.str() << std::endl;
228 op = new SetChunkOp(m_op, &context, oid.str(), oid2.str(), m_stats);
11fdf7f2
TL
229 return true;
230 }
231 } else if (m_op == make_manifest_end + 1) {
232 int set_size = context.oid_not_in_use.size();
233 int set_manifest_size = context.oid_redirect_not_in_use.size();
234 cout << m_op << " oid_not_in_use " << set_size << " oid_redirect_not_in_use " << set_manifest_size << std::endl;
235 /* wait for redirect or set_chunk initialization */
236 if (set_size != m_objects || set_manifest_size != 0) {
237 op = NULL;
238 m_op--;
239 cout << m_op << " wait for manifest initialization " << std::endl;
240 return true;
241 }
242 for (int t_op = m_objects+1; t_op <= m_objects*2; t_op++) {
243 stringstream oid;
244 oid << t_op << " " << context.low_tier_pool_name;
245 if (t_op % 2) {
246 oid << " " << string(300, 'm');
247 }
248 cout << " redirect_not_in_use: " << oid.str() << std::endl;
249 context.oid_redirect_not_in_use.insert(oid.str());
250 }
9f95a23c 251 }
11fdf7f2
TL
252
253 return false;
254 }
255
7c673cae
FG
256private:
257
258 TestOp *gen_op(RadosTestContext &context, TestOpType type)
259 {
260 string oid, oid2;
11fdf7f2 261 ceph_assert(context.oid_not_in_use.size());
7c673cae
FG
262
263 switch (type) {
264 case TEST_OP_READ:
265 oid = *(rand_choose(context.oid_not_in_use));
9f95a23c
TL
266 return new ReadOp(m_op, &context, oid, m_balance_reads, m_localize_reads,
267 m_stats);
7c673cae
FG
268
269 case TEST_OP_WRITE:
270 oid = *(rand_choose(context.oid_not_in_use));
271 cout << m_op << ": " << "write oid " << oid << " current snap is "
272 << context.current_snap << std::endl;
273 return new WriteOp(m_op, &context, oid, false, false, m_stats);
274
275 case TEST_OP_WRITE_EXCL:
276 oid = *(rand_choose(context.oid_not_in_use));
277 cout << m_op << ": " << "write (excl) oid "
278 << oid << " current snap is "
279 << context.current_snap << std::endl;
280 return new WriteOp(m_op, &context, oid, false, true, m_stats);
281
282 case TEST_OP_WRITESAME:
283 oid = *(rand_choose(context.oid_not_in_use));
284 cout << m_op << ": " << "writesame oid "
285 << oid << " current snap is "
286 << context.current_snap << std::endl;
287 return new WriteSameOp(m_op, &context, oid, m_stats);
288
289 case TEST_OP_DELETE:
290 oid = *(rand_choose(context.oid_not_in_use));
291 cout << m_op << ": " << "delete oid " << oid << " current snap is "
292 << context.current_snap << std::endl;
293 return new DeleteOp(m_op, &context, oid, m_stats);
294
295 case TEST_OP_SNAP_CREATE:
296 cout << m_op << ": " << "snap_create" << std::endl;
297 return new SnapCreateOp(m_op, &context, m_stats);
298
299 case TEST_OP_SNAP_REMOVE:
300 if (context.snaps.size() <= context.snaps_in_use.size()) {
301 return NULL;
302 }
303 while (true) {
304 int snap = rand_choose(context.snaps)->first;
305 if (context.snaps_in_use.lookup(snap))
306 continue; // in use; try again!
307 cout << m_op << ": " << "snap_remove snap " << snap << std::endl;
308 return new SnapRemoveOp(m_op, &context, snap, m_stats);
309 }
310
311 case TEST_OP_ROLLBACK:
312 {
313 string oid = *(rand_choose(context.oid_not_in_use));
314 cout << m_op << ": " << "rollback oid " << oid << " current snap is "
315 << context.current_snap << std::endl;
316 return new RollbackOp(m_op, &context, oid);
317 }
318
319 case TEST_OP_SETATTR:
320 oid = *(rand_choose(context.oid_not_in_use));
321 cout << m_op << ": " << "setattr oid " << oid
322 << " current snap is " << context.current_snap << std::endl;
323 return new SetAttrsOp(m_op, &context, oid, m_stats);
324
325 case TEST_OP_RMATTR:
326 oid = *(rand_choose(context.oid_not_in_use));
327 cout << m_op << ": " << "rmattr oid " << oid
328 << " current snap is " << context.current_snap << std::endl;
329 return new RemoveAttrsOp(m_op, &context, oid, m_stats);
330
331 case TEST_OP_WATCH:
332 oid = *(rand_choose(context.oid_not_in_use));
333 cout << m_op << ": " << "watch oid " << oid
334 << " current snap is " << context.current_snap << std::endl;
335 return new WatchOp(m_op, &context, oid, m_stats);
336
337 case TEST_OP_COPY_FROM:
338 oid = *(rand_choose(context.oid_not_in_use));
339 do {
340 oid2 = *(rand_choose(context.oid_not_in_use));
341 } while (oid == oid2);
342 cout << m_op << ": " << "copy_from oid " << oid << " from oid " << oid2
343 << " current snap is " << context.current_snap << std::endl;
344 return new CopyFromOp(m_op, &context, oid, oid2, m_stats);
345
346 case TEST_OP_HIT_SET_LIST:
347 {
348 uint32_t hash = rjhash32(rand());
349 cout << m_op << ": " << "hit_set_list " << hash << std::endl;
350 return new HitSetListOp(m_op, &context, hash, m_stats);
351 }
352
353 case TEST_OP_UNDIRTY:
354 {
355 oid = *(rand_choose(context.oid_not_in_use));
356 cout << m_op << ": " << "undirty oid " << oid << std::endl;
357 return new UndirtyOp(m_op, &context, oid, m_stats);
358 }
359
360 case TEST_OP_IS_DIRTY:
361 {
362 oid = *(rand_choose(context.oid_not_flushing));
363 return new IsDirtyOp(m_op, &context, oid, m_stats);
364 }
365
366 case TEST_OP_CACHE_FLUSH:
367 {
368 oid = *(rand_choose(context.oid_not_in_use));
369 return new CacheFlushOp(m_op, &context, oid, m_stats, true);
370 }
371
372 case TEST_OP_CACHE_TRY_FLUSH:
373 {
374 oid = *(rand_choose(context.oid_not_in_use));
375 return new CacheFlushOp(m_op, &context, oid, m_stats, false);
376 }
377
378 case TEST_OP_CACHE_EVICT:
379 {
380 oid = *(rand_choose(context.oid_not_in_use));
381 return new CacheEvictOp(m_op, &context, oid, m_stats);
382 }
383
384 case TEST_OP_APPEND:
385 oid = *(rand_choose(context.oid_not_in_use));
386 cout << "append oid " << oid << " current snap is "
387 << context.current_snap << std::endl;
388 return new WriteOp(m_op, &context, oid, true, false, m_stats);
389
390 case TEST_OP_APPEND_EXCL:
391 oid = *(rand_choose(context.oid_not_in_use));
392 cout << "append oid (excl) " << oid << " current snap is "
393 << context.current_snap << std::endl;
394 return new WriteOp(m_op, &context, oid, true, true, m_stats);
395
11fdf7f2
TL
396 case TEST_OP_CHUNK_READ:
397 oid = *(rand_choose(context.oid_not_in_use));
398 cout << m_op << ": " << "chunk read oid " << oid << " target oid " << oid2 << std::endl;
399 return new ChunkReadOp(m_op, &context, oid, context.pool_name, false, m_stats);
400
401 case TEST_OP_TIER_PROMOTE:
402 oid = *(rand_choose(context.oid_not_in_use));
403 cout << m_op << ": " << "tier_promote oid " << oid << std::endl;
404 return new TierPromoteOp(m_op, &context, oid, m_stats);
405
9f95a23c
TL
406 case TEST_OP_TIER_FLUSH:
407 oid = *(rand_choose(context.oid_not_in_use));
408 cout << m_op << ": " << "tier_flush oid " << oid << std::endl;
409 return new TierFlushOp(m_op, &context, oid, m_stats);
410
31f18b77
FG
411 case TEST_OP_SET_REDIRECT:
412 oid = *(rand_choose(context.oid_not_in_use));
413 oid2 = *(rand_choose(context.oid_redirect_not_in_use));
414 cout << m_op << ": " << "set_redirect oid " << oid << " target oid " << oid2 << std::endl;
415 return new SetRedirectOp(m_op, &context, oid, oid2, context.pool_name, m_stats);
416
417 case TEST_OP_UNSET_REDIRECT:
418 oid = *(rand_choose(context.oid_not_in_use));
419 cout << m_op << ": " << "unset_redirect oid " << oid << std::endl;
420 return new UnsetRedirectOp(m_op, &context, oid, m_stats);
421
20effc67
TL
422 case TEST_OP_SET_CHUNK:
423 {
424 ceph_assert(m_enable_dedup);
425 oid = *(rand_choose(context.oid_not_in_use));
426 cout << m_op << ": " << "set_chunk oid " << oid
427 << " target oid " << std::endl;
428 return new SetChunkOp(m_op, &context, oid, "", m_stats);
429 }
430
431 case TEST_OP_TIER_EVICT:
432 oid = *(rand_choose(context.oid_not_in_use));
433 cout << m_op << ": " << "tier_evict oid " << oid << std::endl;
434 return new TierEvictOp(m_op, &context, oid, m_stats);
435
7c673cae
FG
436 default:
437 cerr << m_op << ": Invalid op type " << type << std::endl;
438 ceph_abort();
439 return nullptr;
440 }
441 }
442
443 TestOp *m_nextop;
444 int m_op;
445 int m_ops;
446 int m_seconds;
447 int m_objects;
448 time_t m_start;
449 TestOpStat *m_stats;
450 map<TestOpType, unsigned int> m_weight_sums;
451 unsigned int m_total_weight;
452 bool m_ec_pool;
453 bool m_balance_reads;
9f95a23c 454 bool m_localize_reads;
31f18b77 455 bool m_set_redirect;
11fdf7f2 456 bool m_set_chunk;
9f95a23c 457 bool m_enable_dedup;
7c673cae
FG
458};
459
460int main(int argc, char **argv)
461{
462 int ops = 1000;
463 int objects = 50;
464 int max_in_flight = 16;
465 int64_t size = 4000000; // 4 MB
466 int64_t min_stride_size = -1, max_stride_size = -1;
467 int max_seconds = 0;
468 bool pool_snaps = false;
469 bool write_fadvise_dontneed = false;
470
471 struct {
472 TestOpType op;
473 const char *name;
474 bool ec_pool_valid;
475 } op_types[] = {
476 { TEST_OP_READ, "read", true },
477 { TEST_OP_WRITE, "write", false },
478 { TEST_OP_WRITE_EXCL, "write_excl", false },
479 { TEST_OP_WRITESAME, "writesame", false },
480 { TEST_OP_DELETE, "delete", true },
481 { TEST_OP_SNAP_CREATE, "snap_create", true },
482 { TEST_OP_SNAP_REMOVE, "snap_remove", true },
483 { TEST_OP_ROLLBACK, "rollback", true },
484 { TEST_OP_SETATTR, "setattr", true },
485 { TEST_OP_RMATTR, "rmattr", true },
486 { TEST_OP_WATCH, "watch", true },
487 { TEST_OP_COPY_FROM, "copy_from", true },
488 { TEST_OP_HIT_SET_LIST, "hit_set_list", true },
489 { TEST_OP_IS_DIRTY, "is_dirty", true },
490 { TEST_OP_UNDIRTY, "undirty", true },
491 { TEST_OP_CACHE_FLUSH, "cache_flush", true },
492 { TEST_OP_CACHE_TRY_FLUSH, "cache_try_flush", true },
493 { TEST_OP_CACHE_EVICT, "cache_evict", true },
494 { TEST_OP_APPEND, "append", true },
495 { TEST_OP_APPEND_EXCL, "append_excl", true },
31f18b77
FG
496 { TEST_OP_SET_REDIRECT, "set_redirect", true },
497 { TEST_OP_UNSET_REDIRECT, "unset_redirect", true },
11fdf7f2
TL
498 { TEST_OP_CHUNK_READ, "chunk_read", true },
499 { TEST_OP_TIER_PROMOTE, "tier_promote", true },
9f95a23c 500 { TEST_OP_TIER_FLUSH, "tier_flush", true },
20effc67
TL
501 { TEST_OP_SET_CHUNK, "set_chunk", true },
502 { TEST_OP_TIER_EVICT, "tier_evict", true },
7c673cae
FG
503 { TEST_OP_READ /* grr */, NULL },
504 };
505
20effc67
TL
506 struct {
507 const char *name;
508 } chunk_algo_types[] = {
509 { "fastcdc" },
510 { "fixcdc" },
511 };
512
7c673cae
FG
513 map<TestOpType, unsigned int> op_weights;
514 string pool_name = "rbd";
11fdf7f2 515 string low_tier_pool_name = "";
7c673cae
FG
516 bool ec_pool = false;
517 bool no_omap = false;
518 bool no_sparse = false;
519 bool balance_reads = false;
9f95a23c 520 bool localize_reads = false;
31f18b77 521 bool set_redirect = false;
11fdf7f2 522 bool set_chunk = false;
9f95a23c 523 bool enable_dedup = false;
20effc67
TL
524 string chunk_algo = "";
525 string chunk_size = "";
526
7c673cae
FG
527
528 for (int i = 1; i < argc; ++i) {
529 if (strcmp(argv[i], "--max-ops") == 0)
530 ops = atoi(argv[++i]);
531 else if (strcmp(argv[i], "--pool") == 0)
532 pool_name = argv[++i];
533 else if (strcmp(argv[i], "--max-seconds") == 0)
534 max_seconds = atoi(argv[++i]);
535 else if (strcmp(argv[i], "--objects") == 0)
536 objects = atoi(argv[++i]);
537 else if (strcmp(argv[i], "--max-in-flight") == 0)
538 max_in_flight = atoi(argv[++i]);
539 else if (strcmp(argv[i], "--size") == 0)
540 size = atoi(argv[++i]);
541 else if (strcmp(argv[i], "--min-stride-size") == 0)
542 min_stride_size = atoi(argv[++i]);
543 else if (strcmp(argv[i], "--max-stride-size") == 0)
544 max_stride_size = atoi(argv[++i]);
545 else if (strcmp(argv[i], "--no-omap") == 0)
546 no_omap = true;
547 else if (strcmp(argv[i], "--no-sparse") == 0)
548 no_sparse = true;
9f95a23c 549 else if (strcmp(argv[i], "--balance-reads") == 0)
7c673cae 550 balance_reads = true;
9f95a23c
TL
551 else if (strcmp(argv[i], "--localize-reads") == 0)
552 localize_reads = true;
7c673cae
FG
553 else if (strcmp(argv[i], "--pool-snaps") == 0)
554 pool_snaps = true;
555 else if (strcmp(argv[i], "--write-fadvise-dontneed") == 0)
556 write_fadvise_dontneed = true;
557 else if (strcmp(argv[i], "--ec-pool") == 0) {
558 if (!op_weights.empty()) {
559 cerr << "--ec-pool must be specified prior to any ops" << std::endl;
560 exit(1);
561 }
562 ec_pool = true;
563 no_omap = true;
564 no_sparse = true;
565 } else if (strcmp(argv[i], "--op") == 0) {
566 i++;
567 if (i == argc) {
568 cerr << "Missing op after --op" << std::endl;
569 return 1;
570 }
571 int j;
572 for (j = 0; op_types[j].name; ++j) {
573 if (strcmp(op_types[j].name, argv[i]) == 0) {
574 break;
575 }
576 }
577 if (!op_types[j].name) {
578 cerr << "unknown op " << argv[i] << std::endl;
579 exit(1);
580 }
581 i++;
582 if (i == argc) {
583 cerr << "Weight unspecified." << std::endl;
584 return 1;
585 }
586 int weight = atoi(argv[i]);
587 if (weight < 0) {
588 cerr << "Weights must be nonnegative." << std::endl;
589 return 1;
590 } else if (weight > 0) {
591 if (ec_pool && !op_types[j].ec_pool_valid) {
592 cerr << "Error: cannot use op type " << op_types[j].name
593 << " with --ec-pool" << std::endl;
594 exit(1);
595 }
596 cout << "adding op weight " << op_types[j].name << " -> " << weight << std::endl;
597 op_weights.insert(pair<TestOpType, unsigned int>(op_types[j].op, weight));
598 }
31f18b77
FG
599 } else if (strcmp(argv[i], "--set_redirect") == 0) {
600 set_redirect = true;
11fdf7f2
TL
601 } else if (strcmp(argv[i], "--set_chunk") == 0) {
602 set_chunk = true;
603 } else if (strcmp(argv[i], "--low_tier_pool") == 0) {
604 /*
605 * disallow redirect or chunk object into the same pool
606 * to prevent the race. see https://github.com/ceph/ceph/pull/20096
607 */
608 low_tier_pool_name = argv[++i];
9f95a23c
TL
609 } else if (strcmp(argv[i], "--enable_dedup") == 0) {
610 enable_dedup = true;
20effc67
TL
611 } else if (strcmp(argv[i], "--dedup_chunk_algo") == 0) {
612 i++;
613 if (i == argc) {
614 cerr << "Missing chunking algorithm after --dedup_chunk_algo" << std::endl;
615 return 1;
616 }
617 int j;
618 for (j = 0; chunk_algo_types[j].name; ++j) {
619 if (strcmp(chunk_algo_types[j].name, argv[i]) == 0) {
620 break;
621 }
622 }
623 if (!chunk_algo_types[j].name) {
624 cerr << "unknown op " << argv[i] << std::endl;
625 exit(1);
626 }
627 chunk_algo = chunk_algo_types[j].name;
628 } else if (strcmp(argv[i], "--dedup_chunk_size") == 0) {
629 chunk_size = argv[++i];
7c673cae
FG
630 } else {
631 cerr << "unknown arg " << argv[i] << std::endl;
7c673cae
FG
632 exit(1);
633 }
634 }
635
11fdf7f2
TL
636 if (set_redirect || set_chunk) {
637 if (low_tier_pool_name == "") {
9f95a23c 638 cerr << "low_tier_pool is needed" << std::endl;
11fdf7f2
TL
639 exit(1);
640 }
641 }
642
20effc67
TL
643 if (enable_dedup) {
644 if (chunk_algo == "" || chunk_size == "") {
645 cerr << "Missing chunking algorithm: " << chunk_algo
646 << " or chunking size: " << chunk_size << std::endl;
647 exit(1);
648 }
649 }
650
7c673cae
FG
651 if (op_weights.empty()) {
652 cerr << "No operations specified" << std::endl;
7c673cae
FG
653 exit(1);
654 }
655
656 if (min_stride_size < 0)
657 min_stride_size = size / 10;
658 if (max_stride_size < 0)
659 max_stride_size = size / 5;
660
661 cout << pretty_version_to_str() << std::endl;
662 cout << "Configuration:" << std::endl
663 << "\tNumber of operations: " << ops << std::endl
664 << "\tNumber of objects: " << objects << std::endl
665 << "\tMax in flight operations: " << max_in_flight << std::endl
666 << "\tObject size (in bytes): " << size << std::endl
667 << "\tWrite stride min: " << min_stride_size << std::endl
668 << "\tWrite stride max: " << max_stride_size << std::endl;
669
c07f9fc5
FG
670 if (min_stride_size >= max_stride_size) {
671 cerr << "Error: max_stride_size must be more than min_stride_size"
7c673cae
FG
672 << std::endl;
673 return 1;
674 }
675
676 if (min_stride_size > size || max_stride_size > size) {
677 cerr << "Error: min_stride_size and max_stride_size must be "
678 << "smaller than object size" << std::endl;
679 return 1;
680 }
681
682 if (max_in_flight * 2 > objects) {
683 cerr << "Error: max_in_flight must be <= than the number of objects / 2"
684 << std::endl;
685 return 1;
686 }
687
688 char *id = getenv("CEPH_CLIENT_ID");
689 RadosTestContext context(
690 pool_name,
691 max_in_flight,
692 size,
693 min_stride_size,
694 max_stride_size,
695 no_omap,
696 no_sparse,
697 pool_snaps,
698 write_fadvise_dontneed,
11fdf7f2 699 low_tier_pool_name,
9f95a23c 700 enable_dedup,
20effc67
TL
701 chunk_algo,
702 chunk_size,
7c673cae
FG
703 id);
704
705 TestOpStat stats;
706 WeightedTestGenerator gen = WeightedTestGenerator(
707 ops, objects,
708 op_weights, &stats, max_seconds,
9f95a23c
TL
709 ec_pool, balance_reads, localize_reads,
710 set_redirect, set_chunk, enable_dedup);
7c673cae
FG
711 int r = context.init();
712 if (r < 0) {
713 cerr << "Error initializing rados test context: "
714 << cpp_strerror(r) << std::endl;
715 exit(1);
716 }
717 context.loop(&gen);
20effc67
TL
718 if (enable_dedup) {
719 if (!context.check_chunks_refcount(context.low_tier_io_ctx, context.io_ctx)) {
720 cerr << " Invalid refcount " << std::endl;
721 exit(1);
722 }
723 }
7c673cae
FG
724
725 context.shutdown();
726 cerr << context.errors << " errors." << std::endl;
727 cerr << stats << std::endl;
728 return 0;
729}