1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2012 New Dream Network
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.
19 #include "common/ceph_argparse.h"
20 #include "global/global_init.h"
21 #include "common/debug.h"
22 #include "os/filestore/FileStore.h"
24 #include "DeterministicOpSequence.h"
25 #include "FileStoreDiff.h"
27 #include "common/config.h"
28 #include "include/ceph_assert.h"
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_
33 #define dout_prefix *_dout << "test_idempotent_sequence "
37 void usage(const char *name
, std::string command
= "") {
38 ceph_assert(name
!= NULL
);
40 std::string more
= "cmd <args...>";
41 std::string diff
= "diff <filestoreA> <journalA> <filestoreB> <journalB>";
42 std::string get_last_op
= "get-last-op <filestore> <journal>";
43 std::string run_seq_to
= "run-sequence-to <num-ops> <filestore> <journal>";
45 if (!command
.empty()) {
46 if (command
== "diff")
48 else if (command
== "get-last-op")
50 else if (command
== "run-sequence-to")
53 std::cout
<< "usage: " << name
<< " " << more
<< " [options]" << std::endl
;
58 " << get_last_op
<< "\n\
59 " << run_seq_to
<< "\n\
62 -c FILE Read configuration from FILE\n\
63 --osd-data PATH Set OSD Data path\n\
64 --osd-journal PATH Set OSD Journal path\n\
65 --osd-journal-size VAL Set Journal size\n\
66 --help This message\n\
68 Test-specific Options:\n\
69 --test-seed VAL Seed to run the test\n\
70 --test-status-file PATH Path to keep the status file\n\
71 --test-num-colls VAL Number of collections to create on init\n\
72 --test-num-objs VAL Number of objects to create on init\n\
76 const char *our_name
= NULL
;
77 int seed
= 0, num_txs
= 100, num_colls
= 30, num_objs
= 0;
78 bool is_seed_set
= false;
80 std::string status_file
;
82 int run_diff(std::string
& a_path
, std::string
& a_journal
,
83 std::string
& b_path
, std::string
& b_journal
)
85 FileStore
*a
= new FileStore(g_ceph_context
, a_path
, a_journal
, 0, "a");
86 FileStore
*b
= new FileStore(g_ceph_context
, b_path
, b_journal
, 0, "b");
90 FileStoreDiff
fsd(a
, b
);
92 dout(0) << "diff found an difference" << dendl
;
95 dout(0) << "no diff" << dendl
;
104 int run_get_last_op(std::string
& filestore_path
, std::string
& journal_path
)
106 FileStore
*store
= new FileStore(g_ceph_context
, filestore_path
,
109 int err
= store
->mount();
117 store
->list_collections(cls
);
120 for (auto cid
: cls
) {
121 ghobject_t txn_object
= DeterministicOpSequence::get_txn_object(cid
);
123 auto ch
= store
->open_collection(cid
);
124 store
->read(ch
, txn_object
, 0, 100, bl
);
127 auto p
= bl
.cbegin();
138 cout
<< txn
<< std::endl
;
142 int run_sequence_to(int val
, std::string
& filestore_path
,
143 std::string
& journal_path
)
148 seed
= (int) time(NULL
);
150 FileStore
*store
= new FileStore(g_ceph_context
, filestore_path
,
155 // mkfs iff directory dne
156 err
= ::mkdir(filestore_path
.c_str(), 0755);
158 cerr
<< filestore_path
<< " already exists" << std::endl
;
165 ceph_assert(err
== 0);
167 err
= store
->mount();
168 ceph_assert(err
== 0);
170 DeterministicOpSequence
op_sequence(store
, status_file
);
171 op_sequence
.init(num_colls
, num_objs
);
172 op_sequence
.generate(seed
, num_txs
);
177 int run_command(std::string
& command
, std::vector
<std::string
>& args
)
179 if (command
.empty()) {
184 /* We'll have a class that will handle the options, the command
185 * and its arguments. For the time being, and so we can move on, let's
186 * tolerate this big, ugly code.
188 if (command
== "diff") {
189 /* expect 4 arguments: (filestore path + journal path)*2 */
190 if (args
.size() == 4) {
191 return run_diff(args
[0], args
[1], args
[2], args
[3]);
193 } else if (command
== "get-last-op") {
194 /* expect 2 arguments: a filestore path + journal */
195 if (args
.size() == 2) {
196 return run_get_last_op(args
[0], args
[1]);
198 } else if (command
== "run-sequence-to") {
199 /* expect 3 arguments: # of operations and a filestore path + journal. */
200 if (args
.size() == 3) {
201 return run_sequence_to(strtoll(args
[0].c_str(), NULL
, 10), args
[1], args
[2]);
204 std::cout
<< "unknown command " << command
<< std::endl
;
209 usage(our_name
, command
);
213 int main(int argc
, const char *argv
[])
216 auto args
= argv_to_vec(argc
, argv
);
218 auto cct
= global_init(NULL
, args
,
219 CEPH_ENTITY_TYPE_CLIENT
, CODE_ENVIRONMENT_UTILITY
,
220 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
);
221 common_init_finish(g_ceph_context
);
222 g_ceph_context
->_conf
.apply_changes(nullptr);
225 std::vector
<std::string
> command_args
;
227 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end();) {
230 if (ceph_argparse_double_dash(args
, i
)) {
232 } else if (ceph_argparse_witharg(args
, i
, &val
,
233 "--test-seed", (char*) NULL
)) {
234 seed
= strtoll(val
.c_str(), NULL
, 10);
236 } else if (ceph_argparse_witharg(args
, i
, &val
,
237 "--test-num-colls", (char*) NULL
)) {
238 num_colls
= strtoll(val
.c_str(), NULL
, 10);
239 } else if (ceph_argparse_witharg(args
, i
, &val
,
240 "--test-num-objs", (char*) NULL
)) {
241 num_objs
= strtoll(val
.c_str(), NULL
, 10);
242 } else if (ceph_argparse_witharg(args
, i
, &val
,
243 "--test-status-file", (char*) NULL
)) {
245 } else if (ceph_argparse_flag(args
, i
, "--help", (char*) NULL
)) {
252 command_args
.push_back(string(*i
++));
256 int ret
= run_command(command
, command_args
);