]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/objectstore/test_idempotent_sequence.cc
import quincy beta 17.1.0
[ceph.git] / 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/ceph_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 using namespace std;
36
37 void usage(const char *name, std::string command = "") {
38 ceph_assert(name != NULL);
39
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>";
44
45 if (!command.empty()) {
46 if (command == "diff")
47 more = diff;
48 else if (command == "get-last-op")
49 more = get_last_op;
50 else if (command == "run-sequence-to")
51 more = run_seq_to;
52 }
53 std::cout << "usage: " << name << " " << more << " [options]" << std::endl;
54
55 std::cout << "\n\
56 Commands:\n\
57 " << diff << "\n\
58 " << get_last_op << "\n\
59 " << run_seq_to << "\n\
60 \n\
61 Global Options:\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\
67 \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\
73 " << std::endl;
74 }
75
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;
79 int verify_at = 0;
80 std::string status_file;
81
82 int run_diff(std::string& a_path, std::string& a_journal,
83 std::string& b_path, std::string& b_journal)
84 {
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");
87
88 int ret = 0;
89 {
90 FileStoreDiff fsd(a, b);
91 if (fsd.diff()) {
92 dout(0) << "diff found an difference" << dendl;
93 ret = -1;
94 } else {
95 dout(0) << "no diff" << dendl;
96 }
97 }
98
99 delete a;
100 delete b;
101 return ret;
102 }
103
104 int run_get_last_op(std::string& filestore_path, std::string& journal_path)
105 {
106 FileStore *store = new FileStore(g_ceph_context, filestore_path,
107 journal_path);
108
109 int err = store->mount();
110 if (err) {
111 store->umount();
112 delete store;
113 return err;
114 }
115
116 vector<coll_t> cls;
117 store->list_collections(cls);
118
119 int32_t txn = 0;
120 for (auto cid : cls) {
121 ghobject_t txn_object = DeterministicOpSequence::get_txn_object(cid);
122 bufferlist bl;
123 auto ch = store->open_collection(cid);
124 store->read(ch, txn_object, 0, 100, bl);
125 int32_t t = 0;
126 if (bl.length()) {
127 auto p = bl.cbegin();
128 decode(t, p);
129 }
130 if (t > txn) {
131 txn = t;
132 }
133 }
134
135 store->umount();
136 delete store;
137
138 cout << txn << std::endl;
139 return 0;
140 }
141
142 int run_sequence_to(int val, std::string& filestore_path,
143 std::string& journal_path)
144 {
145 num_txs = val;
146
147 if (!is_seed_set)
148 seed = (int) time(NULL);
149
150 FileStore *store = new FileStore(g_ceph_context, filestore_path,
151 journal_path);
152
153 int err;
154
155 // mkfs iff directory dne
156 err = ::mkdir(filestore_path.c_str(), 0755);
157 if (err) {
158 cerr << filestore_path << " already exists" << std::endl;
159 store->umount();
160 delete store;
161 return err;
162 }
163
164 err = store->mkfs();
165 ceph_assert(err == 0);
166
167 err = store->mount();
168 ceph_assert(err == 0);
169
170 DeterministicOpSequence op_sequence(store, status_file);
171 op_sequence.init(num_colls, num_objs);
172 op_sequence.generate(seed, num_txs);
173 store->umount();
174 return 0;
175 }
176
177 int run_command(std::string& command, std::vector<std::string>& args)
178 {
179 if (command.empty()) {
180 usage(our_name);
181 exit(0);
182 }
183
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.
187 */
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]);
192 }
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]);
197 }
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]);
202 }
203 } else {
204 std::cout << "unknown command " << command << std::endl;
205 usage(our_name);
206 exit(1);
207 }
208
209 usage(our_name, command);
210 exit(1);
211 }
212
213 int main(int argc, const char *argv[])
214 {
215 our_name = argv[0];
216 auto args = argv_to_vec(argc, argv);
217
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);
223
224 std::string command;
225 std::vector<std::string> command_args;
226
227 for (std::vector<const char*>::iterator i = args.begin(); i != args.end();) {
228 string val;
229
230 if (ceph_argparse_double_dash(args, i)) {
231 break;
232 } else if (ceph_argparse_witharg(args, i, &val,
233 "--test-seed", (char*) NULL)) {
234 seed = strtoll(val.c_str(), NULL, 10);
235 is_seed_set = true;
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)) {
244 status_file = val;
245 } else if (ceph_argparse_flag(args, i, "--help", (char*) NULL)) {
246 usage(our_name);
247 exit(0);
248 } else {
249 if (command.empty())
250 command = *i++;
251 else
252 command_args.push_back(string(*i++));
253 }
254 }
255
256 int ret = run_command(command, command_args);
257
258 return ret;
259 }