Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / objectstore / test_idempotent_sequence.cc
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) 2012 New Dream Network
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 #include <stdio.h>
14 #include <string.h>
15 #include <iostream>
16 #include <sstream>
17 #include <time.h>
18 #include <stdlib.h>
19 #include "common/ceph_argparse.h"
20 #include "global/global_init.h"
21 #include "common/debug.h"
22 #include "os/filestore/FileStore.h"
23
24 #include "DeterministicOpSequence.h"
25 #include "FileStoreDiff.h"
26
27 #include "common/config.h"
28 #include "include/assert.h"
29
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_
32 #undef dout_prefix
33 #define dout_prefix *_dout << "test_idempotent_sequence "
34
35 void usage(const char *name, std::string command = "") {
36   assert(name != NULL);
37
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>";
42
43   if (!command.empty()) {
44     if (command == "diff")
45       more = diff;
46     else if (command == "get-last-op")
47       more = get_last_op;
48     else if (command == "run-sequence-to")
49       more = run_seq_to;
50   }
51   std::cout << "usage: " << name << " " << more << " [options]" << std::endl;
52
53   std::cout << "\n\
54 Commands:\n\
55   " << diff << "\n\
56   " << get_last_op << "\n\
57   " << run_seq_to << "\n\
58 \n\
59 Global Options:\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\
65 \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\
71 " << std::endl;
72 }
73
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;
77 int verify_at = 0;
78 std::string status_file;
79
80 int run_diff(std::string& a_path, std::string& a_journal,
81              std::string& b_path, std::string& b_journal)
82 {
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");
85
86   int ret = 0;
87   {
88     FileStoreDiff fsd(a, b);
89     if (fsd.diff()) {
90       dout(0) << "diff found an difference" << dendl;
91       ret = -1;
92     } else {
93       dout(0) << "no diff" << dendl;
94     }
95   }
96
97   delete a;
98   delete b;
99   return ret;
100 }
101
102 int run_get_last_op(std::string& filestore_path, std::string& journal_path)
103 {
104   FileStore *store = new FileStore(g_ceph_context, filestore_path,
105                                    journal_path);
106
107   int err = store->mount();
108   if (err) {
109     store->umount();
110     delete store;
111     return err;
112   }
113
114   coll_t txn_coll;
115   ghobject_t txn_object(hobject_t(sobject_t("txn", CEPH_NOSNAP)));
116   bufferlist bl;
117   store->read(txn_coll, txn_object, 0, 100, bl);
118   int32_t txn = 0;
119   if (bl.length()) {
120     bufferlist::iterator p = bl.begin();
121     ::decode(txn, p);
122   }
123
124   store->umount();
125   delete store;
126
127   cout << txn << std::endl;
128   return 0;
129 }
130
131 int run_sequence_to(int val, std::string& filestore_path,
132                      std::string& journal_path)
133 {
134   num_txs = val;
135
136   if (!is_seed_set)
137     seed = (int) time(NULL);
138
139   FileStore *store = new FileStore(g_ceph_context, filestore_path,
140                                    journal_path);
141
142   int err;
143
144   // mkfs iff directory dne
145   err = ::mkdir(filestore_path.c_str(), 0755);
146   if (err) {
147     cerr << filestore_path << " already exists" << std::endl;
148     store->umount();
149     delete store;
150     return err;
151   }
152   
153   err = store->mkfs();
154   ceph_assert(err == 0);
155
156   err = store->mount();
157   ceph_assert(err == 0);
158
159   DeterministicOpSequence op_sequence(store, status_file);
160   op_sequence.init(num_colls, num_objs);
161   op_sequence.generate(seed, num_txs);
162   store->umount();
163   return 0;
164 }
165
166 int run_command(std::string& command, std::vector<std::string>& args)
167 {
168   if (command.empty()) {
169     usage(our_name);
170     exit(0);
171   }
172
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.
176    */
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]);
181     }
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]);
186     }
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]);
191     }
192   } else {
193     std::cout << "unknown command " << command << std::endl;
194     usage(our_name);
195     exit(1);
196   }
197
198   usage(our_name, command);
199   exit(1);
200 }
201
202 int main(int argc, const char *argv[])
203 {
204   vector<const char*> def_args;
205   vector<const char*> args;
206   our_name = argv[0];
207   argv_to_vec(argc, argv, args);
208
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);
214
215   std::string command;
216   std::vector<std::string> command_args;
217
218   for (std::vector<const char*>::iterator i = args.begin(); i != args.end();) {
219     string val;
220
221     if (ceph_argparse_double_dash(args, i)) {
222       break;
223     } else if (ceph_argparse_witharg(args, i, &val,
224         "--test-seed", (char*) NULL)) {
225       seed = strtoll(val.c_str(), NULL, 10);
226       is_seed_set = true;
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)) {
235       status_file = val;
236     } else if (ceph_argparse_flag(args, i, "--help", (char*) NULL)) {
237       usage(our_name);
238       exit(0);
239     } else {
240       if (command.empty())
241         command = *i++;
242       else
243         command_args.push_back(string(*i++));
244     }
245   }
246
247   int ret = run_command(command, command_args);
248
249   return ret;
250 }