]>
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) 2014 Adam Crume <adamcrume@gmail.com> | |
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 | */ | |
14 | ||
15 | #include <vector> | |
16 | #include <boost/thread.hpp> | |
17 | #include "common/ceph_argparse.h" | |
18 | #include "global/global_init.h" | |
19 | #include "Replayer.hpp" | |
20 | #include "rbd_replay_debug.hpp" | |
21 | #include "ImageNameMap.hpp" | |
22 | ||
23 | ||
7c673cae FG |
24 | using namespace rbd_replay; |
25 | ||
26 | ||
27 | static const char* get_remainder(const char *string, const char *prefix) { | |
28 | while (*prefix) { | |
29 | if (*prefix++ != *string++) { | |
30 | return NULL; | |
31 | } | |
32 | } | |
33 | return string; | |
34 | } | |
35 | ||
36 | static void usage(const char* program) { | |
37 | cout << "Usage: " << program << " --conf=<config_file> <replay_file>" << std::endl; | |
38 | cout << "Options:" << std::endl; | |
39 | cout << " -p, --pool-name <pool> Name of the pool to use. Default: rbd" << std::endl; | |
40 | cout << " --latency-multiplier <float> Multiplies inter-request latencies. Default: 1" << std::endl; | |
41 | cout << " --read-only Only perform non-destructive operations." << std::endl; | |
42 | cout << " --map-image <rule> Add a rule to map image names in the trace to" << std::endl; | |
43 | cout << " image names in the replay cluster." << std::endl; | |
44 | cout << " --dump-perf-counters *Experimental*" << std::endl; | |
45 | cout << " Dump performance counters to standard out before" << std::endl; | |
46 | cout << " an image is closed. Performance counters may be dumped" << std::endl; | |
47 | cout << " multiple times if multiple images are closed, or if" << std::endl; | |
48 | cout << " the same image is opened and closed multiple times." << std::endl; | |
49 | cout << " Performance counters and their meaning may change between" << std::endl; | |
50 | cout << " versions." << std::endl; | |
51 | cout << std::endl; | |
52 | cout << "Image mapping rules:" << std::endl; | |
53 | cout << "A rule of image1@snap1=image2@snap2 would map snap1 of image1 to snap2 of" << std::endl; | |
54 | cout << "image2." << std::endl; | |
55 | } | |
56 | ||
57 | int main(int argc, const char **argv) { | |
58 | vector<const char*> args; | |
59 | ||
60 | argv_to_vec(argc, argv, args); | |
11fdf7f2 TL |
61 | if (args.empty()) { |
62 | cerr << argv[0] << ": -h or --help for usage" << std::endl; | |
63 | exit(1); | |
64 | } | |
65 | if (ceph_argparse_need_usage(args)) { | |
66 | usage(argv[0]); | |
67 | exit(0); | |
68 | } | |
7c673cae FG |
69 | auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, |
70 | CODE_ENVIRONMENT_UTILITY, 0); | |
71 | ||
72 | std::vector<const char*>::iterator i; | |
31f18b77 | 73 | string pool_name; |
7c673cae FG |
74 | float latency_multiplier = 1; |
75 | bool readonly = false; | |
76 | ImageNameMap image_name_map; | |
77 | std::string val; | |
78 | std::ostringstream err; | |
79 | bool dump_perf_counters = false; | |
80 | for (i = args.begin(); i != args.end(); ) { | |
81 | if (ceph_argparse_double_dash(args, i)) { | |
82 | break; | |
83 | } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) { | |
84 | pool_name = val; | |
85 | } else if (ceph_argparse_witharg(args, i, &latency_multiplier, err, "--latency-multiplier", | |
86 | (char*)NULL)) { | |
87 | if (!err.str().empty()) { | |
88 | cerr << err.str() << std::endl; | |
89 | return 1; | |
90 | } | |
91 | } else if (ceph_argparse_flag(args, i, "--read-only", (char*)NULL)) { | |
92 | readonly = true; | |
93 | } else if (ceph_argparse_witharg(args, i, &val, "--map-image", (char*)NULL)) { | |
94 | ImageNameMap::Mapping mapping; | |
95 | if (image_name_map.parse_mapping(val, &mapping)) { | |
96 | image_name_map.add_mapping(mapping); | |
97 | } else { | |
98 | cerr << "Unable to parse mapping string: '" << val << "'" << std::endl; | |
99 | return 1; | |
100 | } | |
7c673cae FG |
101 | } else if (ceph_argparse_flag(args, i, "--dump-perf-counters", (char*)NULL)) { |
102 | dump_perf_counters = true; | |
103 | } else if (get_remainder(*i, "-")) { | |
104 | cerr << "Unrecognized argument: " << *i << std::endl; | |
105 | return 1; | |
106 | } else { | |
107 | ++i; | |
108 | } | |
109 | } | |
110 | ||
111 | common_init_finish(g_ceph_context); | |
112 | ||
113 | string replay_file; | |
114 | if (!args.empty()) { | |
115 | replay_file = args[0]; | |
116 | } | |
117 | ||
118 | if (replay_file.empty()) { | |
119 | cerr << "No replay file specified." << std::endl; | |
120 | return 1; | |
121 | } | |
122 | ||
123 | unsigned int nthreads = boost::thread::hardware_concurrency(); | |
124 | Replayer replayer(2 * nthreads + 1); | |
125 | replayer.set_latency_multiplier(latency_multiplier); | |
126 | replayer.set_pool_name(pool_name); | |
127 | replayer.set_readonly(readonly); | |
128 | replayer.set_image_name_map(image_name_map); | |
129 | replayer.set_dump_perf_counters(dump_perf_counters); | |
130 | replayer.run(replay_file); | |
131 | } |