1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/buffer.h"
5 #include "include/stringify.h"
6 #include "common/ceph_argparse.h"
7 #include "common/config_proxy.h"
8 #include "common/errno.h"
9 #include "erasure-code/ErasureCode.h"
10 #include "erasure-code/ErasureCodePlugin.h"
11 #include "global/global_context.h"
12 #include "global/global_init.h"
13 #include "osd/ECUtil.h"
20 #include <boost/algorithm/string.hpp>
22 std::vector
<std::string
> display_params
= {
23 "chunk_count", "data_chunk_count", "coding_chunk_count"
26 void usage(const std::string message
, ostream
&out
) {
27 if (!message
.empty()) {
28 out
<< message
<< std::endl
;
29 out
<< "" << std::endl
;
31 out
<< "usage: ceph-erasure-code-tool test-plugin-exists <plugin>" << std::endl
;
32 out
<< " ceph-erasure-code-tool validate-profile <profile> [<display-param> ...]" << std::endl
;
33 out
<< " ceph-erasure-code-tool calc-chunk-size <profile> <object_size>" << std::endl
;
34 out
<< " ceph-erasure-code-tool encode <profile> <stripe_unit> <want_to_encode> <fname>" << std::endl
;
35 out
<< " ceph-erasure-code-tool decode <profile> <stripe_unit> <want_to_decode> <fname>" << std::endl
;
36 out
<< "" << std::endl
;
37 out
<< " plugin - plugin name" << std::endl
;
38 out
<< " profile - comma separated list of erasure-code profile settings" << std::endl
;
39 out
<< " example: plugin=jerasure,technique=reed_sol_van,k=3,m=2" << std::endl
;
40 out
<< " display-param - parameter to display (display all if empty)" << std::endl
;
41 out
<< " may be: " << display_params
<< std::endl
;
42 out
<< " object_size - object size" << std::endl
;
43 out
<< " stripe_unit - stripe unit" << std::endl
;
44 out
<< " want_to_encode - comma separated list of shards to encode" << std::endl
;
45 out
<< " want_to_decode - comma separated list of shards to decode" << std::endl
;
46 out
<< " fname - name for input/output files" << std::endl
;
47 out
<< " when encoding input is read form {fname} file," << std::endl
;
48 out
<< " result is stored in {fname}.{shard} files" << std::endl
;
49 out
<< " when decoding input is read form {fname}.{shard} files," << std::endl
;
50 out
<< " result is stored in {fname} file" << std::endl
;
53 int ec_init(const std::string
&profile_str
,
54 const std::string
&stripe_unit_str
,
55 ceph::ErasureCodeInterfaceRef
*ec_impl
,
56 std::unique_ptr
<ECUtil::stripe_info_t
> *sinfo
) {
57 ceph::ErasureCodeProfile profile
;
58 std::vector
<std::string
> opts
;
59 boost::split(opts
, profile_str
, boost::is_any_of(", "));
60 for (auto &opt_str
: opts
) {
61 std::vector
<std::string
> opt
;
62 boost::split(opt
, opt_str
, boost::is_any_of("="));
63 if (opt
.size() <= 1) {
64 usage("invalid profile", std::cerr
);
67 profile
[opt
[0]] = opt
[1];
69 auto plugin
= profile
.find("plugin");
70 if (plugin
== profile
.end()) {
71 usage("invalid profile: plugin not specified", std::cerr
);
76 ceph::ErasureCodePluginRegistry::instance().factory(
77 plugin
->second
, g_conf().get_val
<std::string
>("erasure_code_dir"),
78 profile
, ec_impl
, &ss
);
80 usage("invalid profile: " + ss
.str(), std::cerr
);
84 if (sinfo
== nullptr) {
88 uint64_t stripe_unit
= atoi(stripe_unit_str
.c_str());
89 if (stripe_unit
<= 0) {
90 usage("invalid stripe unit", std::cerr
);
94 uint64_t stripe_size
= atoi(profile
["k"].c_str());
95 ceph_assert(stripe_size
> 0);
96 uint64_t stripe_width
= stripe_size
* stripe_unit
;
97 sinfo
->reset(new ECUtil::stripe_info_t(stripe_size
, stripe_width
));
102 int do_test_plugin_exists(const std::vector
<const char*> &args
) {
103 if (args
.size() < 1) {
104 usage("not enought arguments", std::cerr
);
108 ErasureCodePluginRegistry
&instance
= ErasureCodePluginRegistry::instance();
109 ErasureCodePlugin
*plugin
;
112 std::lock_guard l
{instance
.lock
};
113 int r
= instance
.load(
114 args
[0], g_conf().get_val
<std::string
>("erasure_code_dir"), &plugin
, &ss
);
115 std::cerr
<< ss
.str() << endl
;
119 int do_validate_profile(const std::vector
<const char*> &args
) {
120 if (args
.size() < 1) {
121 usage("not enought arguments", std::cerr
);
125 ceph::ErasureCodeInterfaceRef ec_impl
;
126 int r
= ec_init(args
[0], {}, &ec_impl
, nullptr);
131 if (args
.size() > 1) {
132 std::set
<std::string
> valid_params(display_params
.begin(),
133 display_params
.end());
134 display_params
.clear();
135 for (size_t i
= 1; i
< args
.size(); i
++) {
136 if (!valid_params
.count(args
[i
])) {
137 usage("invalid display param: " + std::string(args
[i
]), std::cerr
);
140 display_params
.push_back(args
[i
]);
144 for (auto ¶m
: display_params
) {
145 if (display_params
.size() > 1) {
146 std::cout
<< param
<< ": ";
148 if (param
== "chunk_count") {
149 std::cout
<< ec_impl
->get_chunk_count() << std::endl
;
150 } else if (param
== "data_chunk_count") {
151 std::cout
<< ec_impl
->get_data_chunk_count() << std::endl
;
152 } else if (param
== "coding_chunk_count") {
153 std::cout
<< ec_impl
->get_coding_chunk_count() << std::endl
;
155 ceph_abort_msgf("unknown display_param: %s", param
.c_str());
162 int do_calc_chunk_size(const std::vector
<const char*> &args
) {
163 if (args
.size() < 2) {
164 usage("not enought arguments", std::cerr
);
168 ceph::ErasureCodeInterfaceRef ec_impl
;
169 int r
= ec_init(args
[0], {}, &ec_impl
, nullptr);
174 uint64_t object_size
= atoi(args
[1]);
175 if (object_size
<= 0) {
176 usage("invalid object size", std::cerr
);
180 std::cout
<< ec_impl
->get_chunk_size(object_size
) << std::endl
;
184 int do_encode(const std::vector
<const char*> &args
) {
185 if (args
.size() < 4) {
186 usage("not enought arguments", std::cerr
);
190 ceph::ErasureCodeInterfaceRef ec_impl
;
191 std::unique_ptr
<ECUtil::stripe_info_t
> sinfo
;
192 int r
= ec_init(args
[0], args
[1], &ec_impl
, &sinfo
);
198 std::vector
<std::string
> shards
;
199 boost::split(shards
, args
[2], boost::is_any_of(","));
200 for (auto &shard
: shards
) {
201 want
.insert(atoi(shard
.c_str()));
203 ceph::bufferlist decoded_data
;
204 std::string fname
= args
[3];
207 r
= decoded_data
.read_file(fname
.c_str(), &error
);
209 std::cerr
<< "failed to read " << fname
<< ": " << error
<< std::endl
;
213 uint64_t stripe_width
= sinfo
->get_stripe_width();
214 if (decoded_data
.length() % stripe_width
!= 0) {
215 uint64_t pad
= stripe_width
- decoded_data
.length() % stripe_width
;
216 decoded_data
.append_zero(pad
);
219 std::map
<int, ceph::bufferlist
> encoded_data
;
220 r
= ECUtil::encode(*sinfo
, ec_impl
, decoded_data
, want
, &encoded_data
);
222 std::cerr
<< "failed to encode: " << cpp_strerror(r
) << std::endl
;
226 for (auto &[shard
, bl
] : encoded_data
) {
227 std::string name
= fname
+ "." + stringify(shard
);
228 r
= bl
.write_file(name
.c_str());
230 std::cerr
<< "failed to write " << name
<< ": " << cpp_strerror(r
)
239 int do_decode(const std::vector
<const char*> &args
) {
240 if (args
.size() < 4) {
241 usage("not enought arguments", std::cerr
);
245 ceph::ErasureCodeInterfaceRef ec_impl
;
246 std::unique_ptr
<ECUtil::stripe_info_t
> sinfo
;
247 int r
= ec_init(args
[0], args
[1], &ec_impl
, &sinfo
);
252 std::map
<int, ceph::bufferlist
> encoded_data
;
253 std::vector
<std::string
> shards
;
254 boost::split(shards
, args
[2], boost::is_any_of(","));
255 for (auto &shard
: shards
) {
256 encoded_data
[atoi(shard
.c_str())] = {};
258 ceph::bufferlist decoded_data
;
259 std::string fname
= args
[3];
261 for (auto &[shard
, bl
] : encoded_data
) {
262 std::string name
= fname
+ "." + stringify(shard
);
264 r
= bl
.read_file(name
.c_str(), &error
);
266 std::cerr
<< "failed to read " << name
<< ": " << error
<< std::endl
;
271 r
= ECUtil::decode(*sinfo
, ec_impl
, encoded_data
, &decoded_data
);
273 std::cerr
<< "failed to decode: " << cpp_strerror(r
) << std::endl
;
277 r
= decoded_data
.write_file(fname
.c_str());
279 std::cerr
<< "failed to write " << fname
<< ": " << cpp_strerror(r
)
287 int main(int argc
, const char **argv
) {
288 std::vector
<const char*> args
;
289 argv_to_vec(argc
, argv
, args
);
290 auto cct
= global_init(nullptr, args
, CEPH_ENTITY_TYPE_CLIENT
,
291 CODE_ENVIRONMENT_UTILITY
,
292 CINIT_FLAG_NO_MON_CONFIG
);
294 if (args
.empty() || args
[0] == std::string("-h") ||
295 args
[0] == std::string("--help")) {
296 usage("", std::cout
);
300 if (args
.size() < 1) {
301 usage("not enought arguments", std::cerr
);
305 std::string cmd
= args
[0];
306 std::vector
<const char*> cmd_args(args
.begin() + 1, args
.end());
308 if (cmd
== "test-plugin-exists") {
309 return do_test_plugin_exists(cmd_args
);
310 } else if (cmd
== "validate-profile") {
311 return do_validate_profile(cmd_args
);
312 } else if (cmd
== "calc-chunk-size") {
313 return do_calc_chunk_size(cmd_args
);
314 } else if (cmd
== "encode") {
315 return do_encode(cmd_args
);
316 } else if (cmd
== "decode") {
317 return do_decode(cmd_args
);
320 usage("invalid command: " + cmd
, std::cerr
);