]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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" | |
11fdf7f2 | 28 | #include "include/ceph_assert.h" |
7c673cae FG |
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 | ||
20effc67 TL |
35 | using namespace std; |
36 | ||
7c673cae | 37 | void usage(const char *name, std::string command = "") { |
11fdf7f2 | 38 | ceph_assert(name != NULL); |
7c673cae FG |
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 | ||
11fdf7f2 TL |
116 | vector<coll_t> cls; |
117 | store->list_collections(cls); | |
118 | ||
7c673cae | 119 | int32_t txn = 0; |
11fdf7f2 TL |
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 | } | |
7c673cae FG |
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 | { | |
7c673cae | 215 | our_name = argv[0]; |
20effc67 | 216 | auto args = argv_to_vec(argc, argv); |
7c673cae | 217 | |
11fdf7f2 | 218 | auto cct = global_init(NULL, args, |
7c673cae FG |
219 | CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, |
220 | CINIT_FLAG_NO_DEFAULT_CONFIG_FILE); | |
221 | common_init_finish(g_ceph_context); | |
11fdf7f2 | 222 | g_ceph_context->_conf.apply_changes(nullptr); |
7c673cae FG |
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 | } |