1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2015 Red Hat
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.
17 #include "include/types.h"
19 #include "include/encoding.h"
20 #include "include/ceph_features.h"
21 #include "common/ceph_argparse.h"
22 #include "common/Formatter.h"
23 #include "common/errno.h"
24 #include "msg/Message.h"
25 #include "include/assert.h"
28 #define TYPE_STRAYDATA(t)
29 #define TYPE_NONDETERMINISTIC(t)
30 #define TYPE_FEATUREFUL(t)
31 #define TYPE_FEATUREFUL_STRAYDATA(t)
32 #define TYPE_FEATUREFUL_NONDETERMINISTIC(t)
33 #define TYPE_FEATUREFUL_NOCOPY(t)
34 #define TYPE_NOCOPY(t)
39 #undef TYPE_NONDETERMINISTIC
41 #undef TYPE_FEATUREFUL
42 #undef TYPE_FEATUREFUL_STRAYDATA
43 #undef TYPE_FEATUREFUL_NONDETERMINISTIC
44 #undef TYPE_FEATUREFUL_NOCOPY
47 #define MB(m) ((m) * 1024 * 1024)
49 void usage(ostream
&out
)
51 out
<< "usage: ceph-dencoder [commands ...]" << std::endl
;
53 out
<< " version print version string (to stdout)\n";
55 out
<< " import <encfile> read encoded data from encfile\n";
56 out
<< " export <outfile> write encoded data to outfile\n";
58 out
<< " set_features <num> set feature bits used for encoding\n";
59 out
<< " get_features print feature bits (int) to stdout\n";
61 out
<< " list_types list supported types\n";
62 out
<< " type <classname> select in-memory type\n";
63 out
<< " skip <num> skip <num> leading bytes before decoding\n";
64 out
<< " decode decode into in-memory object\n";
65 out
<< " encode encode in-memory object\n";
66 out
<< " dump_json dump in-memory object as json (to stdout)\n";
67 out
<< " hexdump print encoded data in hex\n";
69 out
<< " copy copy object (via operator=)\n";
70 out
<< " copy_ctor copy object (via copy ctor)\n";
72 out
<< " count_tests print number of generated test objects (to stdout)\n";
73 out
<< " select_test <n> select generated test object as in-memory object\n";
74 out
<< " is_deterministic exit w/ success if type encodes deterministically\n";
77 virtual ~Dencoder() {}
78 virtual string
decode(bufferlist bl
, uint64_t seek
) = 0;
79 virtual void encode(bufferlist
& out
, uint64_t features
) = 0;
80 virtual void dump(ceph::Formatter
*f
) = 0;
82 cerr
<< "copy operator= not supported" << std::endl
;
84 virtual void copy_ctor() {
85 cerr
<< "copy ctor not supported" << std::endl
;
87 virtual void generate() = 0;
88 virtual int num_generated() = 0;
89 virtual string
select_generated(unsigned n
) = 0;
90 virtual bool is_deterministic() = 0;
91 //virtual void print(ostream& out) = 0;
95 class DencoderBase
: public Dencoder
{
100 bool nondeterministic
;
103 DencoderBase(bool stray_okay
, bool nondeterministic
)
105 stray_okay(stray_okay
),
106 nondeterministic(nondeterministic
) {}
107 ~DencoderBase() override
{
111 string
decode(bufferlist bl
, uint64_t seek
) override
{
112 bufferlist::iterator p
= bl
.begin();
115 ::decode(*m_object
, p
);
117 catch (buffer::error
& e
) {
120 if (!stray_okay
&& !p
.end()) {
122 ss
<< "stray data at end of buffer, offset " << p
.get_off();
128 void encode(bufferlist
& out
, uint64_t features
) override
= 0;
130 void dump(ceph::Formatter
*f
) override
{
133 void generate() override
{
134 T::generate_test_instances(m_list
);
136 int num_generated() override
{
137 return m_list
.size();
139 string
select_generated(unsigned i
) override
{
140 // allow 0- or 1-based (by wrapping)
143 if ((i
== 0) || (i
> m_list
.size()))
144 return "invalid id for generated object";
145 typename list
<T
*>::iterator p
= m_list
.begin();
146 for (i
--; i
> 0 && p
!= m_list
.end(); ++p
, --i
) ;
151 bool is_deterministic() override
{
152 return !nondeterministic
;
157 class DencoderImplNoFeatureNoCopy
: public DencoderBase
<T
> {
159 DencoderImplNoFeatureNoCopy(bool stray_ok
, bool nondeterministic
)
160 : DencoderBase
<T
>(stray_ok
, nondeterministic
) {}
161 void encode(bufferlist
& out
, uint64_t features
) override
{
163 ::encode(*this->m_object
, out
);
168 class DencoderImplNoFeature
: public DencoderImplNoFeatureNoCopy
<T
> {
170 DencoderImplNoFeature(bool stray_ok
, bool nondeterministic
)
171 : DencoderImplNoFeatureNoCopy
<T
>(stray_ok
, nondeterministic
) {}
172 void copy() override
{
174 *n
= *this->m_object
;
175 delete this->m_object
;
178 void copy_ctor() override
{
179 T
*n
= new T(*this->m_object
);
180 delete this->m_object
;
186 class DencoderImplFeaturefulNoCopy
: public DencoderBase
<T
> {
188 DencoderImplFeaturefulNoCopy(bool stray_ok
, bool nondeterministic
)
189 : DencoderBase
<T
>(stray_ok
, nondeterministic
) {}
190 void encode(bufferlist
& out
, uint64_t features
) override
{
192 ::encode(*(this->m_object
), out
, features
);
197 class DencoderImplFeatureful
: public DencoderImplFeaturefulNoCopy
<T
> {
199 DencoderImplFeatureful(bool stray_ok
, bool nondeterministic
)
200 : DencoderImplFeaturefulNoCopy
<T
>(stray_ok
, nondeterministic
) {}
201 void copy() override
{
203 *n
= *this->m_object
;
204 delete this->m_object
;
207 void copy_ctor() override
{
208 T
*n
= new T(*this->m_object
);
209 delete this->m_object
;
215 class MessageDencoderImpl
: public Dencoder
{
220 MessageDencoderImpl() {
223 ~MessageDencoderImpl() override
{
227 string
decode(bufferlist bl
, uint64_t seek
) override
{
228 bufferlist::iterator p
= bl
.begin();
231 Message
*n
= decode_message(g_ceph_context
, 0, p
);
233 throw std::runtime_error("failed to decode");
234 if (n
->get_type() != m_object
->get_type()) {
236 ss
<< "decoded type " << n
->get_type() << " instead of expected " << m_object
->get_type();
237 throw std::runtime_error(ss
.str());
240 m_object
= static_cast<T
*>(n
);
242 catch (buffer::error
& e
) {
247 ss
<< "stray data at end of buffer, offset " << p
.get_off();
253 void encode(bufferlist
& out
, uint64_t features
) override
{
255 encode_message(m_object
, features
, out
);
258 void dump(ceph::Formatter
*f
) override
{
261 void generate() override
{
262 //T::generate_test_instances(m_list);
264 int num_generated() override
{
265 return m_list
.size();
267 string
select_generated(unsigned i
) override
{
268 // allow 0- or 1-based (by wrapping)
271 if ((i
== 0) || (i
> m_list
.size()))
272 return "invalid id for generated object";
273 typename list
<T
*>::iterator p
= m_list
.begin();
274 for (i
--; i
> 0 && p
!= m_list
.end(); ++p
, --i
) ;
279 bool is_deterministic() override
{
283 //void print(ostream& out) {
284 //out << m_object << std::endl;
290 int main(int argc
, const char **argv
)
293 map
<string
,Dencoder
*> dencoders
;
296 #define T_STRINGIFY(x) T_STR(x)
297 #define TYPE(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(false, false);
298 #define TYPE_STRAYDATA(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(true, false);
299 #define TYPE_NONDETERMINISTIC(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(false, true);
300 #define TYPE_FEATUREFUL(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(false, false);
301 #define TYPE_FEATUREFUL_STRAYDATA(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(true, false);
302 #define TYPE_FEATUREFUL_NONDETERMINISTIC(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(false, true);
303 #define TYPE_FEATUREFUL_NOCOPY(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeaturefulNoCopy<t>(false, false);
304 #define TYPE_NOCOPY(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeatureNoCopy<t>(false, false);
305 #define MESSAGE(t) dencoders[T_STRINGIFY(t)] = new MessageDencoderImpl<t>;
308 #undef TYPE_STRAYDATA
309 #undef TYPE_NONDETERMINISTIC
311 #undef TYPE_FEATUREFUL
312 #undef TYPE_FEATUREFUL_STRAYDATA
313 #undef TYPE_FEATUREFUL_NONDETERMINISTIC
314 #undef TYPE_FEATUREFUL_NOCOPY
318 vector
<const char*> args
;
319 argv_to_vec(argc
, argv
, args
);
322 Dencoder
*den
= NULL
;
323 uint64_t features
= CEPH_FEATURES_SUPPORTED_DEFAULT
;
328 cerr
<< "-h for help" << std::endl
;
331 for (std::vector
<const char*>::iterator i
= args
.begin(); i
!= args
.end(); ++i
) {
334 if (*i
== string("help") || *i
== string("-h") || *i
== string("--help")) {
337 } else if (*i
== string("version")) {
338 cout
<< CEPH_GIT_NICE_VER
<< std::endl
;
339 } else if (*i
== string("list_types")) {
340 for (map
<string
,Dencoder
*>::iterator p
= dencoders
.begin();
341 p
!= dencoders
.end();
343 cout
<< p
->first
<< std::endl
;
345 } else if (*i
== string("type")) {
347 if (i
== args
.end()) {
348 cerr
<< "expecting type" << std::endl
;
352 if (!dencoders
.count(cname
)) {
353 cerr
<< "class '" << cname
<< "' unknown" << std::endl
;
356 den
= dencoders
[cname
];
358 } else if (*i
== string("skip")) {
360 if (i
== args
.end()) {
361 cerr
<< "expecting byte count" << std::endl
;
365 } else if (*i
== string("get_features")) {
366 cout
<< CEPH_FEATURES_SUPPORTED_DEFAULT
<< std::endl
;
368 } else if (*i
== string("set_features")) {
370 if (i
== args
.end()) {
371 cerr
<< "expecting features" << std::endl
;
374 features
= atoll(*i
);
375 } else if (*i
== string("encode")) {
377 cerr
<< "must first select type with 'type <name>'" << std::endl
;
380 den
->encode(encbl
, features
| CEPH_FEATURE_RESERVED
); // hack for OSDMap
381 } else if (*i
== string("decode")) {
383 cerr
<< "must first select type with 'type <name>'" << std::endl
;
386 err
= den
->decode(encbl
, skip
);
387 } else if (*i
== string("copy_ctor")) {
389 cerr
<< "must first select type with 'type <name>'" << std::endl
;
393 } else if (*i
== string("copy")) {
395 cerr
<< "must first select type with 'type <name>'" << std::endl
;
399 } else if (*i
== string("dump_json")) {
401 cerr
<< "must first select type with 'type <name>'" << std::endl
;
404 JSONFormatter
jf(true);
405 jf
.open_object_section("object");
411 } else if (*i
== string("hexdump")) {
413 } else if (*i
== string("import")) {
415 if (i
== args
.end()) {
416 cerr
<< "expecting filename" << std::endl
;
420 if (*i
== string("-")) {
422 // Read up to 1mb if stdin specified
423 r
= encbl
.read_fd(STDIN_FILENO
, MB(1));
425 r
= encbl
.read_file(*i
, &err
);
428 cerr
<< "error reading " << *i
<< ": " << err
<< std::endl
;
432 } else if (*i
== string("export")) {
434 if (i
== args
.end()) {
435 cerr
<< "expecting filename" << std::endl
;
438 int fd
= ::open(*i
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
440 cerr
<< "error opening " << *i
<< " for write: " << cpp_strerror(errno
) << std::endl
;
443 int r
= encbl
.write_fd(fd
);
445 cerr
<< "error writing " << *i
<< ": " << cpp_strerror(errno
) << std::endl
;
450 } else if (*i
== string("count_tests")) {
452 cerr
<< "must first select type with 'type <name>'" << std::endl
;
455 cout
<< den
->num_generated() << std::endl
;
456 } else if (*i
== string("select_test")) {
458 cerr
<< "must first select type with 'type <name>'" << std::endl
;
462 if (i
== args
.end()) {
463 cerr
<< "expecting instance number" << std::endl
;
467 err
= den
->select_generated(n
);
468 } else if (*i
== string("is_deterministic")) {
470 cerr
<< "must first select type with 'type <name>'" << std::endl
;
473 if (den
->is_deterministic())
478 cerr
<< "unknown option '" << *i
<< "'" << std::endl
;
482 cerr
<< "error: " << err
<< std::endl
;