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/assert.h"
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_
33 #define dout_prefix *_dout << "test_idempotent_sequence "
35 void usage(const char *name, std::string command = "") {
38 std::string more = "cmd <args...>";
39 std::string diff = "diff <filestoreA> <journalA> <filestoreB> <journalB>";
40 std::string get_last_op = "get-last-op <filestore> <journal>";
41 std::string run_seq_to = "run-sequence-to <num-ops> <filestore> <journal>";
43 if (!command.empty()) {
44 if (command == "diff")
46 else if (command == "get-last-op")
48 else if (command == "run-sequence-to")
51 std::cout << "usage: " << name << " " << more << " [options]" << std::endl;
56 " << get_last_op << "\n\
57 " << run_seq_to << "\n\
60 -c FILE Read configuration from FILE\n\
61 --osd-data PATH Set OSD Data path\n\
62 --osd-journal PATH Set OSD Journal path\n\
63 --osd-journal-size VAL Set Journal size\n\
64 --help This message\n\
66 Test-specific Options:\n\
67 --test-seed VAL Seed to run the test\n\
68 --test-status-file PATH Path to keep the status file\n\
69 --test-num-colls VAL Number of collections to create on init\n\
70 --test-num-objs VAL Number of objects to create on init\n\
74 const char *our_name = NULL;
75 int seed = 0, num_txs = 100, num_colls = 30, num_objs = 0;
76 bool is_seed_set = false;
78 std::string status_file;
80 int run_diff(std::string& a_path, std::string& a_journal,
81 std::string& b_path, std::string& b_journal)
83 FileStore *a = new FileStore(g_ceph_context, a_path, a_journal, 0, "a");
84 FileStore *b = new FileStore(g_ceph_context, b_path, b_journal, 0, "b");
88 FileStoreDiff fsd(a, b);
90 dout(0) << "diff found an difference" << dendl;
93 dout(0) << "no diff" << dendl;
102 int run_get_last_op(std::string& filestore_path, std::string& journal_path)
104 FileStore *store = new FileStore(g_ceph_context, filestore_path,
107 int err = store->mount();
115 ghobject_t txn_object(hobject_t(sobject_t("txn", CEPH_NOSNAP)));
117 store->read(txn_coll, txn_object, 0, 100, bl);
120 bufferlist::iterator p = bl.begin();
127 cout << txn << std::endl;
131 int run_sequence_to(int val, std::string& filestore_path,
132 std::string& journal_path)
137 seed = (int) time(NULL);
139 FileStore *store = new FileStore(g_ceph_context, filestore_path,
144 // mkfs iff directory dne
145 err = ::mkdir(filestore_path.c_str(), 0755);
147 cerr << filestore_path << " already exists" << std::endl;
154 ceph_assert(err == 0);
156 err = store->mount();
157 ceph_assert(err == 0);
159 DeterministicOpSequence op_sequence(store, status_file);
160 op_sequence.init(num_colls, num_objs);
161 op_sequence.generate(seed, num_txs);
166 int run_command(std::string& command, std::vector<std::string>& args)
168 if (command.empty()) {
173 /* We'll have a class that will handle the options, the command
174 * and its arguments. For the time being, and so we can move on, let's
175 * tolerate this big, ugly code.
177 if (command == "diff") {
178 /* expect 4 arguments: (filestore path + journal path)*2 */
179 if (args.size() == 4) {
180 return run_diff(args[0], args[1], args[2], args[3]);
182 } else if (command == "get-last-op") {
183 /* expect 2 arguments: a filestore path + journal */
184 if (args.size() == 2) {
185 return run_get_last_op(args[0], args[1]);
187 } else if (command == "run-sequence-to") {
188 /* expect 3 arguments: # of operations and a filestore path + journal. */
189 if (args.size() == 3) {
190 return run_sequence_to(strtoll(args[0].c_str(), NULL, 10), args[1], args[2]);
193 std::cout << "unknown command " << command << std::endl;
198 usage(our_name, command);
202 int main(int argc, const char *argv[])
204 vector<const char*> def_args;
205 vector<const char*> args;
207 argv_to_vec(argc, argv, args);
209 auto cct = global_init(&def_args, args,
210 CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY,
211 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
212 common_init_finish(g_ceph_context);
213 g_ceph_context->_conf->apply_changes(NULL);
216 std::vector<std::string> command_args;
218 for (std::vector<const char*>::iterator i = args.begin(); i != args.end();) {
221 if (ceph_argparse_double_dash(args, i)) {
223 } else if (ceph_argparse_witharg(args, i, &val,
224 "--test-seed", (char*) NULL)) {
225 seed = strtoll(val.c_str(), NULL, 10);
227 } else if (ceph_argparse_witharg(args, i, &val,
228 "--test-num-colls", (char*) NULL)) {
229 num_colls = strtoll(val.c_str(), NULL, 10);
230 } else if (ceph_argparse_witharg(args, i, &val,
231 "--test-num-objs", (char*) NULL)) {
232 num_objs = strtoll(val.c_str(), NULL, 10);
233 } else if (ceph_argparse_witharg(args, i, &val,
234 "--test-status-file", (char*) NULL)) {
236 } else if (ceph_argparse_flag(args, i, "--help", (char*) NULL)) {
243 command_args.push_back(string(*i++));
247 int ret = run_command(command, command_args);