mds: Add encode/decode/dump for use with dencoder

This is for the MDSTable subclasses: AnchorServer,
SnapServer, InoTable.  AnchorServer was partially there
but didn't work in practice dumped objects because of
the version prefix on the object.

This adds a skip argument to ceph-dencoder for getting
past fixed size prefixes.  The encode_server_state method
is also made const to avoid the need for const_casting (and
because it really is const)

Signed-off-by: John Spray <john.spray@inktank.com>
This commit is contained in:
John Spray 2014-02-05 23:17:29 +00:00
parent c5c7f6c8e8
commit 541beb87dc
12 changed files with 225 additions and 16 deletions

View File

@ -45,6 +45,11 @@ Commands
Select the given type for future ``encode`` or ``decode`` operations.
.. option:: skip <bytes>
Seek <bytes> into the imported file before reading data structure, use
this with objects that have a preamble/header before the object of interest.
.. option:: decode
Decode the contents of the in-memory buffer into an instance of the
@ -84,7 +89,9 @@ Commands
Example
=======
Say you want to examine an attribute on an object stored by ``ceph-osd``. You can do::
Say you want to examine an attribute on an object stored by ``ceph-osd``. You can do this:
::
$ cd /mnt/osd.12/current/2.b_head
$ attr -l foo_bar_head_EFE6384B
@ -113,6 +120,21 @@ Say you want to examine an attribute on an object stored by ``ceph-osd``. You c
"truncate_size": 0,
"watchers": {}}
Alternatively, perhaps you wish to dump an internal CephFS metadata object, you might
do that like this:
::
$ rados -p metadata get mds_snaptable mds_snaptable.bin
$ ceph-dencoder type SnapServer skip 8 import mds_snaptable.bin decode dump_json
{ "snapserver": { "last_snap": 1,
"pending_noop": [],
"snaps": [],
"need_to_purge": {},
"pending_create": [],
"pending_destroy": []}}
Availability
============

View File

@ -33,7 +33,7 @@ class AnchorServer : public MDSTableServer {
map<inodeno_t, list<pair<version_t, Context*> > > pending_ops;
void reset_state();
void encode_server_state(bufferlist& bl) {
void encode_server_state(bufferlist& bl) const {
ENCODE_START(2, 2, bl);
::encode(anchor_map, bl);
::encode(pending_create, bl);
@ -70,10 +70,11 @@ class AnchorServer : public MDSTableServer {
// for the dencoder
AnchorServer() : MDSTableServer(NULL, TABLE_ANCHOR) {}
void encode(bufferlist& bl) const {
AnchorServer *me = const_cast<AnchorServer*>(this);
me->encode_server_state(bl);
encode_server_state(bl);
}
void decode(bufferlist::iterator& bl) {
decode_server_state(bl);
}
void decode(bufferlist::iterator& bl) { decode_server_state(bl); }
// server bits
void _prepare(bufferlist &bl, uint64_t reqid, int bymds);

View File

@ -156,3 +156,34 @@ void InoTable::skip_inos(inodeno_t i)
projected_version = ++version;
dout(10) << "skip_inos now " << free << dendl;
}
void InoTable::dump(Formatter *f) const
{
f->open_object_section("inotable");
f->open_array_section("projected_free");
for (interval_set<inodeno_t>::const_iterator i = projected_free.begin(); i != projected_free.end(); ++i) {
f->open_object_section("range");
f->dump_int("start", (*i).first);
f->dump_int("len", (*i).second);
f->close_section();
}
f->close_section();
f->open_array_section("free");
for (interval_set<inodeno_t>::const_iterator i = free.begin(); i != free.end(); ++i) {
f->open_object_section("range");
f->dump_int("start", (*i).first);
f->dump_int("len", (*i).second);
f->close_section();
}
f->close_section();
f->close_section();
}
void InoTable::generate_test_instances(list<InoTable*>& ls)
{
ls.push_back(new InoTable());
}

View File

@ -43,7 +43,7 @@ class InoTable : public MDSTable {
void replay_reset();
void reset_state();
void encode_state(bufferlist& bl) {
void encode_state(bufferlist& bl) const {
ENCODE_START(2, 2, bl);
::encode(free, bl);
ENCODE_FINISH(bl);
@ -55,6 +55,17 @@ class InoTable : public MDSTable {
DECODE_FINISH(bl);
}
// To permit enc/decoding in isolation in dencoder
InoTable() : MDSTable(NULL, "inotable", true) {}
void encode(bufferlist& bl) const {
encode_state(bl);
}
void decode(bufferlist::iterator& bl) {
decode_state(bl);
}
void dump(Formatter *f) const;
static void generate_test_instances(list<InoTable*>& ls);
void skip_inos(inodeno_t i);
};

View File

@ -27,7 +27,7 @@
#define dout_subsys ceph_subsys_mds
#undef dout_prefix
#define dout_prefix *_dout << "mds." << mds->get_nodeid() << "." << table_name << ": "
#define dout_prefix *_dout << "mds." << (mds ? mds->get_nodeid() : -1) << "." << table_name << ": "
class C_MT_Save : public Context {

View File

@ -79,7 +79,7 @@ public:
// child must overload these
virtual void reset_state() = 0;
virtual void decode_state(bufferlist::iterator& p) = 0;
virtual void encode_state(bufferlist& bl) = 0;
virtual void encode_state(bufferlist& bl) const = 0;
};
#endif

View File

@ -77,10 +77,10 @@ private:
void handle_request(MMDSTableRequest *m);
void do_server_update(bufferlist& bl);
virtual void encode_server_state(bufferlist& bl) = 0;
virtual void encode_server_state(bufferlist& bl) const = 0;
virtual void decode_server_state(bufferlist::iterator& bl) = 0;
void encode_state(bufferlist& bl) {
void encode_state(bufferlist& bl) const {
encode_server_state(bl);
::encode(pending_for_mds, bl);
}

View File

@ -257,3 +257,84 @@ void SnapServer::check_osd_map(bool force)
last_checked_osdmap = version;
}
void SnapServer::dump(Formatter *f) const
{
f->open_object_section("snapserver");
f->dump_int("last_snap", last_snap.val);
f->open_array_section("pending_noop");
for(set<version_t>::const_iterator i = pending_noop.begin(); i != pending_noop.end(); ++i) {
f->dump_unsigned("version", *i);
}
f->close_section();
f->open_array_section("snaps");
for (map<snapid_t, SnapInfo>::const_iterator i = snaps.begin(); i != snaps.end(); ++i) {
f->open_object_section("snap");
i->second.dump(f);
f->close_section();
}
f->close_section();
f->open_object_section("need_to_purge");
for (map<int, set<snapid_t> >::const_iterator i = need_to_purge.begin(); i != need_to_purge.end(); ++i) {
stringstream pool_id;
pool_id << i->first;
f->open_array_section(pool_id.str().c_str());
for (set<snapid_t>::const_iterator s = i->second.begin(); s != i->second.end(); ++s) {
f->dump_unsigned("snapid", s->val);
}
f->close_section();
}
f->close_section();
f->open_array_section("pending_create");
for(map<version_t, SnapInfo>::const_iterator i = pending_create.begin(); i != pending_create.end(); ++i) {
f->open_object_section("snap");
f->dump_unsigned("version", i->first);
f->open_object_section("snapinfo");
i->second.dump(f);
f->close_section();
f->close_section();
}
f->close_section();
f->open_array_section("pending_destroy");
for(map<version_t, pair<snapid_t, snapid_t> >::const_iterator i = pending_destroy.begin(); i != pending_destroy.end(); ++i) {
f->open_object_section("snap");
f->dump_unsigned("version", i->first);
f->dump_unsigned("removed_snap", i->second.first);
f->dump_unsigned("seq", i->second.second);
f->close_section();
}
f->close_section();
f->close_section();
}
void SnapServer::generate_test_instances(list<SnapServer*>& ls)
{
list<SnapInfo*> snapinfo_instances;
SnapInfo::generate_test_instances(snapinfo_instances);
SnapInfo populated_snapinfo = *(snapinfo_instances.back());
for (list<SnapInfo*>::iterator i = snapinfo_instances.begin(); i != snapinfo_instances.end(); ++i) {
delete *i;
}
SnapServer *blank = new SnapServer();
ls.push_back(blank);
SnapServer *populated = new SnapServer();
populated->last_snap = 123;
populated->snaps[456] = populated_snapinfo;
populated->need_to_purge[2].insert(012);
populated->pending_create[234] = populated_snapinfo;
populated->pending_destroy[345].first = 567;
populated->pending_destroy[345].second = 768;
populated->pending_noop.insert(890);
ls.push_back(populated);
}

View File

@ -39,7 +39,7 @@ public:
last_checked_osdmap(0) { }
void reset_state();
void encode_server_state(bufferlist& bl) {
void encode_server_state(bufferlist& bl) const {
ENCODE_START(3, 3, bl);
::encode(last_snap, bl);
::encode(snaps, bl);
@ -67,6 +67,17 @@ public:
DECODE_FINISH(bl);
}
// To permit enc/decoding in isolation in dencoder
SnapServer() : MDSTableServer(NULL, TABLE_SNAP), last_checked_osdmap(0) {}
void encode(bufferlist& bl) const {
encode_server_state(bl);
}
void decode(bufferlist::iterator& bl) {
decode_server_state(bl);
}
void dump(Formatter *f) const;
static void generate_test_instances(list<SnapServer*>& ls);
// server bits
void _prepare(bufferlist &bl, uint64_t reqid, int bymds);
bool _is_prepared(version_t tid);

View File

@ -98,6 +98,38 @@ public:
::decode(write_pos, bl);
::decode(layout, bl);
}
void dump(Formatter *f) const {
f->open_object_section("journal_header");
{
f->dump_string("magic", magic);
f->dump_unsigned("write_pos", write_pos);
f->dump_unsigned("expire_pos", expire_pos);
f->dump_unsigned("trimmed_pos", trimmed_pos);
f->open_object_section("layout");
{
f->dump_unsigned("stripe_unit", layout.fl_stripe_unit);
f->dump_unsigned("stripe_count", layout.fl_stripe_unit);
f->dump_unsigned("object_size", layout.fl_stripe_unit);
f->dump_unsigned("cas_hash", layout.fl_stripe_unit);
f->dump_unsigned("object_stripe_unit", layout.fl_stripe_unit);
f->dump_unsigned("pg_pool", layout.fl_stripe_unit);
}
f->close_section(); // layout
}
f->close_section(); // journal_header
}
static void generate_test_instances(list<Header*> &ls)
{
ls.push_back(new Header());
ls.push_back(new Header());
ls.back()->trimmed_pos = 1;
ls.back()->expire_pos = 2;
ls.back()->unused_field = 3;
ls.back()->write_pos = 4;
ls.back()->magic = "magique";
}
} last_written, last_committed;
WRITE_CLASS_ENCODER(Header)

View File

@ -47,7 +47,7 @@ void usage(ostream &out)
}
struct Dencoder {
virtual ~Dencoder() {}
virtual string decode(bufferlist bl) = 0;
virtual string decode(bufferlist bl, uint64_t seek) = 0;
virtual void encode(bufferlist& out, uint64_t features) = 0;
virtual void dump(ceph::Formatter *f) = 0;
virtual void copy() {
@ -75,8 +75,9 @@ public:
delete m_object;
}
string decode(bufferlist bl) {
string decode(bufferlist bl, uint64_t seek) {
bufferlist::iterator p = bl.begin();
p.seek(seek);
try {
m_object->decode(p);
}
@ -168,8 +169,9 @@ public:
m_object->put();
}
string decode(bufferlist bl) {
string decode(bufferlist bl, uint64_t seek) {
bufferlist::iterator p = bl.begin();
p.seek(seek);
try {
Message *n = decode_message(g_ceph_context, p);
if (!n)
@ -253,6 +255,7 @@ int main(int argc, const char **argv)
Dencoder *den = NULL;
uint64_t features = CEPH_FEATURES_SUPPORTED_DEFAULT;
bufferlist encbl;
uint64_t skip = 0;
if (args.empty()) {
usage(cerr);
@ -285,6 +288,13 @@ int main(int argc, const char **argv)
}
den = dencoders[cname];
den->generate();
} else if (*i == string("skip")) {
++i;
if (i == args.end()) {
usage(cerr);
exit(1);
}
skip = atoi(*i);
} else if (*i == string("get_features")) {
cout << CEPH_FEATURES_SUPPORTED_DEFAULT << std::endl;
exit(0);
@ -309,7 +319,7 @@ int main(int argc, const char **argv)
usage(cerr);
exit(1);
}
err = den->decode(encbl);
err = den->decode(encbl, skip);
} else if (*i == string("copy_ctor")) {
if (!den) {
cerr << "must first select type with 'type <name>'" << std::endl;
@ -348,6 +358,7 @@ int main(int argc, const char **argv)
cerr << "error reading " << *i << ": " << err << std::endl;
exit(1);
}
} else if (*i == string("export")) {
++i;
if (i == args.end()) {

View File

@ -129,6 +129,9 @@ TYPE(MonCap)
TYPE(DBObjectMap::_Header)
TYPE(DBObjectMap::State)
#include "osdc/Journaler.h"
TYPE(Journaler::Header)
#include "mds/Anchor.h"
TYPE(Anchor)
@ -164,7 +167,13 @@ TYPE_FEATUREFUL(MDSMap::mds_info_t)
TYPE_NOCOPY(Capability)
#include "mds/AnchorServer.h"
TYPE(AnchorServer)
TYPEWITHSTRAYDATA(AnchorServer)
#include "mds/InoTable.h"
TYPE(InoTable)
#include "mds/SnapServer.h"
TYPEWITHSTRAYDATA(SnapServer)
#include "mds/SessionMap.h"
TYPE(SessionMap)