]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/encoding/ceph_dencoder.cc
update sources to v12.1.0
[ceph.git] / ceph / src / test / encoding / ceph_dencoder.cc
CommitLineData
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) 2015 Red Hat
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
16#include <errno.h>
17#include "include/types.h"
18#include "ceph_ver.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"
26
27#define TYPE(t)
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)
35#define MESSAGE(t)
36#include "types.h"
37#undef TYPE
38#undef TYPE_STRAYDATA
39#undef TYPE_NONDETERMINISTIC
40#undef TYPE_NOCOPY
41#undef TYPE_FEATUREFUL
42#undef TYPE_FEATUREFUL_STRAYDATA
43#undef TYPE_FEATUREFUL_NONDETERMINISTIC
44#undef TYPE_FEATUREFUL_NOCOPY
45#undef MESSAGE
46
47#define MB(m) ((m) * 1024 * 1024)
48
49void usage(ostream &out)
50{
51 out << "usage: ceph-dencoder [commands ...]" << std::endl;
52 out << "\n";
53 out << " version print version string (to stdout)\n";
54 out << "\n";
55 out << " import <encfile> read encoded data from encfile\n";
56 out << " export <outfile> write encoded data to outfile\n";
57 out << "\n";
58 out << " set_features <num> set feature bits used for encoding\n";
59 out << " get_features print feature bits (int) to stdout\n";
60 out << "\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";
68 out << "\n";
69 out << " copy copy object (via operator=)\n";
70 out << " copy_ctor copy object (via copy ctor)\n";
71 out << "\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";
75}
76struct Dencoder {
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;
81 virtual void copy() {
82 cerr << "copy operator= not supported" << std::endl;
83 }
84 virtual void copy_ctor() {
85 cerr << "copy ctor not supported" << std::endl;
86 }
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;
92};
93
94template<class T>
95class DencoderBase : public Dencoder {
96protected:
97 T* m_object;
98 list<T*> m_list;
99 bool stray_okay;
100 bool nondeterministic;
101
102public:
103 DencoderBase(bool stray_okay, bool nondeterministic)
104 : m_object(new T),
105 stray_okay(stray_okay),
106 nondeterministic(nondeterministic) {}
107 ~DencoderBase() override {
108 delete m_object;
109 }
110
111 string decode(bufferlist bl, uint64_t seek) override {
112 bufferlist::iterator p = bl.begin();
113 p.seek(seek);
114 try {
115 ::decode(*m_object, p);
116 }
117 catch (buffer::error& e) {
118 return e.what();
119 }
120 if (!stray_okay && !p.end()) {
121 ostringstream ss;
122 ss << "stray data at end of buffer, offset " << p.get_off();
123 return ss.str();
124 }
125 return string();
126 }
127
128 void encode(bufferlist& out, uint64_t features) override = 0;
129
130 void dump(ceph::Formatter *f) override {
131 m_object->dump(f);
132 }
133 void generate() override {
134 T::generate_test_instances(m_list);
135 }
136 int num_generated() override {
137 return m_list.size();
138 }
139 string select_generated(unsigned i) override {
140 // allow 0- or 1-based (by wrapping)
141 if (i == 0)
142 i = m_list.size();
143 if ((i == 0) || (i > m_list.size()))
144 return "invalid id for generated object";
31f18b77 145 m_object = *(std::next(m_list.begin(), i-1));
7c673cae
FG
146 return string();
147 }
148
149 bool is_deterministic() override {
150 return !nondeterministic;
151 }
152};
153
154template<class T>
155class DencoderImplNoFeatureNoCopy : public DencoderBase<T> {
156public:
157 DencoderImplNoFeatureNoCopy(bool stray_ok, bool nondeterministic)
158 : DencoderBase<T>(stray_ok, nondeterministic) {}
159 void encode(bufferlist& out, uint64_t features) override {
160 out.clear();
161 ::encode(*this->m_object, out);
162 }
163};
164
165template<class T>
166class DencoderImplNoFeature : public DencoderImplNoFeatureNoCopy<T> {
167public:
168 DencoderImplNoFeature(bool stray_ok, bool nondeterministic)
169 : DencoderImplNoFeatureNoCopy<T>(stray_ok, nondeterministic) {}
170 void copy() override {
171 T *n = new T;
172 *n = *this->m_object;
173 delete this->m_object;
174 this->m_object = n;
175 }
176 void copy_ctor() override {
177 T *n = new T(*this->m_object);
178 delete this->m_object;
179 this->m_object = n;
180 }
181};
182
183template<class T>
184class DencoderImplFeaturefulNoCopy : public DencoderBase<T> {
185public:
186 DencoderImplFeaturefulNoCopy(bool stray_ok, bool nondeterministic)
187 : DencoderBase<T>(stray_ok, nondeterministic) {}
188 void encode(bufferlist& out, uint64_t features) override {
189 out.clear();
190 ::encode(*(this->m_object), out, features);
191 }
192};
193
194template<class T>
195class DencoderImplFeatureful : public DencoderImplFeaturefulNoCopy<T> {
196public:
197 DencoderImplFeatureful(bool stray_ok, bool nondeterministic)
198 : DencoderImplFeaturefulNoCopy<T>(stray_ok, nondeterministic) {}
199 void copy() override {
200 T *n = new T;
201 *n = *this->m_object;
202 delete this->m_object;
203 this->m_object = n;
204 }
205 void copy_ctor() override {
206 T *n = new T(*this->m_object);
207 delete this->m_object;
208 this->m_object = n;
209 }
210};
211
212template<class T>
213class MessageDencoderImpl : public Dencoder {
214 T *m_object;
215 list<T*> m_list;
216
217public:
218 MessageDencoderImpl() {
219 m_object = new T;
220 }
221 ~MessageDencoderImpl() override {
222 m_object->put();
223 }
224
225 string decode(bufferlist bl, uint64_t seek) override {
226 bufferlist::iterator p = bl.begin();
227 p.seek(seek);
228 try {
229 Message *n = decode_message(g_ceph_context, 0, p);
230 if (!n)
231 throw std::runtime_error("failed to decode");
232 if (n->get_type() != m_object->get_type()) {
233 stringstream ss;
234 ss << "decoded type " << n->get_type() << " instead of expected " << m_object->get_type();
235 throw std::runtime_error(ss.str());
236 }
237 m_object->put();
238 m_object = static_cast<T *>(n);
239 }
240 catch (buffer::error& e) {
241 return e.what();
242 }
243 if (!p.end()) {
244 ostringstream ss;
245 ss << "stray data at end of buffer, offset " << p.get_off();
246 return ss.str();
247 }
248 return string();
249 }
250
251 void encode(bufferlist& out, uint64_t features) override {
252 out.clear();
253 encode_message(m_object, features, out);
254 }
255
256 void dump(ceph::Formatter *f) override {
257 m_object->dump(f);
258 }
259 void generate() override {
260 //T::generate_test_instances(m_list);
261 }
262 int num_generated() override {
263 return m_list.size();
264 }
265 string select_generated(unsigned i) override {
266 // allow 0- or 1-based (by wrapping)
267 if (i == 0)
268 i = m_list.size();
269 if ((i == 0) || (i > m_list.size()))
270 return "invalid id for generated object";
7c673cae 271 m_object->put();
31f18b77 272 m_object = *(std::next(m_list.begin(), i-1));
7c673cae
FG
273 return string();
274 }
275 bool is_deterministic() override {
276 return true;
277 }
278
279 //void print(ostream& out) {
280 //out << m_object << std::endl;
281 //}
282};
283
284
285
286int main(int argc, const char **argv)
287{
288 // dencoders
289 map<string,Dencoder*> dencoders;
290
291#define T_STR(x) #x
292#define T_STRINGIFY(x) T_STR(x)
293#define TYPE(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(false, false);
294#define TYPE_STRAYDATA(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(true, false);
295#define TYPE_NONDETERMINISTIC(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeature<t>(false, true);
296#define TYPE_FEATUREFUL(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(false, false);
297#define TYPE_FEATUREFUL_STRAYDATA(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(true, false);
298#define TYPE_FEATUREFUL_NONDETERMINISTIC(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeatureful<t>(false, true);
299#define TYPE_FEATUREFUL_NOCOPY(t) dencoders[T_STRINGIFY(t)] = new DencoderImplFeaturefulNoCopy<t>(false, false);
300#define TYPE_NOCOPY(t) dencoders[T_STRINGIFY(t)] = new DencoderImplNoFeatureNoCopy<t>(false, false);
301#define MESSAGE(t) dencoders[T_STRINGIFY(t)] = new MessageDencoderImpl<t>;
302#include "types.h"
303#undef TYPE
304#undef TYPE_STRAYDATA
305#undef TYPE_NONDETERMINISTIC
306#undef TYPE_NOCOPY
307#undef TYPE_FEATUREFUL
308#undef TYPE_FEATUREFUL_STRAYDATA
309#undef TYPE_FEATUREFUL_NONDETERMINISTIC
310#undef TYPE_FEATUREFUL_NOCOPY
311#undef T_STR
312#undef T_STRINGIFY
313
314 vector<const char*> args;
315 argv_to_vec(argc, argv, args);
316 env_to_vec(args);
317
318 Dencoder *den = NULL;
319 uint64_t features = CEPH_FEATURES_SUPPORTED_DEFAULT;
320 bufferlist encbl;
321 uint64_t skip = 0;
322
323 if (args.empty()) {
324 cerr << "-h for help" << std::endl;
325 exit(1);
326 }
327 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ++i) {
328 string err;
329
330 if (*i == string("help") || *i == string("-h") || *i == string("--help")) {
331 usage(cout);
332 exit(0);
333 } else if (*i == string("version")) {
334 cout << CEPH_GIT_NICE_VER << std::endl;
335 } else if (*i == string("list_types")) {
336 for (map<string,Dencoder*>::iterator p = dencoders.begin();
337 p != dencoders.end();
338 ++p)
339 cout << p->first << std::endl;
340 exit(0);
341 } else if (*i == string("type")) {
342 ++i;
343 if (i == args.end()) {
344 cerr << "expecting type" << std::endl;
345 exit(1);
346 }
347 string cname = *i;
348 if (!dencoders.count(cname)) {
349 cerr << "class '" << cname << "' unknown" << std::endl;
350 exit(1);
351 }
352 den = dencoders[cname];
353 den->generate();
354 } else if (*i == string("skip")) {
355 ++i;
356 if (i == args.end()) {
357 cerr << "expecting byte count" << std::endl;
358 exit(1);
359 }
360 skip = atoi(*i);
361 } else if (*i == string("get_features")) {
362 cout << CEPH_FEATURES_SUPPORTED_DEFAULT << std::endl;
363 exit(0);
364 } else if (*i == string("set_features")) {
365 ++i;
366 if (i == args.end()) {
367 cerr << "expecting features" << std::endl;
368 exit(1);
369 }
370 features = atoll(*i);
371 } else if (*i == string("encode")) {
372 if (!den) {
373 cerr << "must first select type with 'type <name>'" << std::endl;
374 exit(1);
375 }
376 den->encode(encbl, features | CEPH_FEATURE_RESERVED); // hack for OSDMap
377 } else if (*i == string("decode")) {
378 if (!den) {
379 cerr << "must first select type with 'type <name>'" << std::endl;
380 exit(1);
381 }
382 err = den->decode(encbl, skip);
383 } else if (*i == string("copy_ctor")) {
384 if (!den) {
385 cerr << "must first select type with 'type <name>'" << std::endl;
386 exit(1);
387 }
388 den->copy_ctor();
389 } else if (*i == string("copy")) {
390 if (!den) {
391 cerr << "must first select type with 'type <name>'" << std::endl;
392 exit(1);
393 }
394 den->copy();
395 } else if (*i == string("dump_json")) {
396 if (!den) {
397 cerr << "must first select type with 'type <name>'" << std::endl;
398 exit(1);
399 }
400 JSONFormatter jf(true);
401 jf.open_object_section("object");
402 den->dump(&jf);
403 jf.close_section();
404 jf.flush(cout);
405 cout << std::endl;
406
407 } else if (*i == string("hexdump")) {
408 encbl.hexdump(cout);
409 } else if (*i == string("import")) {
410 ++i;
411 if (i == args.end()) {
412 cerr << "expecting filename" << std::endl;
413 exit(1);
414 }
415 int r;
416 if (*i == string("-")) {
417 *i = "stdin";
418 // Read up to 1mb if stdin specified
419 r = encbl.read_fd(STDIN_FILENO, MB(1));
420 } else {
421 r = encbl.read_file(*i, &err);
422 }
423 if (r < 0) {
424 cerr << "error reading " << *i << ": " << err << std::endl;
425 exit(1);
426 }
427
428 } else if (*i == string("export")) {
429 ++i;
430 if (i == args.end()) {
431 cerr << "expecting filename" << std::endl;
432 exit(1);
433 }
434 int fd = ::open(*i, O_WRONLY|O_CREAT|O_TRUNC, 0644);
435 if (fd < 0) {
436 cerr << "error opening " << *i << " for write: " << cpp_strerror(errno) << std::endl;
437 exit(1);
438 }
439 int r = encbl.write_fd(fd);
440 if (r < 0) {
441 cerr << "error writing " << *i << ": " << cpp_strerror(errno) << std::endl;
442 exit(1);
443 }
444 ::close(fd);
445
446 } else if (*i == string("count_tests")) {
447 if (!den) {
448 cerr << "must first select type with 'type <name>'" << std::endl;
449 exit(1);
450 }
451 cout << den->num_generated() << std::endl;
452 } else if (*i == string("select_test")) {
453 if (!den) {
454 cerr << "must first select type with 'type <name>'" << std::endl;
455 exit(1);
456 }
457 ++i;
458 if (i == args.end()) {
459 cerr << "expecting instance number" << std::endl;
460 exit(1);
461 }
462 int n = atoi(*i);
463 err = den->select_generated(n);
464 } else if (*i == string("is_deterministic")) {
465 if (!den) {
466 cerr << "must first select type with 'type <name>'" << std::endl;
467 exit(1);
468 }
469 if (den->is_deterministic())
470 exit(0);
471 else
472 exit(1);
473 } else {
474 cerr << "unknown option '" << *i << "'" << std::endl;
475 exit(1);
476 }
477 if (err.length()) {
478 cerr << "error: " << err << std::endl;
479 exit(1);
480 }
481 }
482 return 0;
483}