From af3aaaebb18a474591d7bc08ade4b2d348c19116 Mon Sep 17 00:00:00 2001 From: Joao Eduardo Luis Date: Fri, 27 Nov 2015 18:41:07 +0000 Subject: [PATCH] mon: MonMap: mon addr and all now held by mon_info_t Instead of keeping several maps mapping back and forth from string to entity_addr_t for each monitor, have the monitor's address and name in purpose-specific class, mon_info_t, and everything references it instead. Although the benefits may not be obvious right now, it will allow us to add other ip addresses for the monitors a bit more easily, instead of having to kludge around the existing structures. We also keep compatibility with older versions by maintaining the traditional 'mon_addr' map. This is a logical change inside the monitor, so we can easily accomodate older monitors without having to rely on quorum features; just needs a bit of care and foo. Signed-off-by: Joao Eduardo Luis --- src/mon/MonMap.cc | 83 +++++++++++--- src/mon/MonMap.h | 273 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 278 insertions(+), 78 deletions(-) diff --git a/src/mon/MonMap.cc b/src/mon/MonMap.cc index dc2503c9393..fe742663294 100644 --- a/src/mon/MonMap.cc +++ b/src/mon/MonMap.cc @@ -18,8 +18,44 @@ using ceph::Formatter; +void mon_info_t::encode(bufferlist& bl, uint64_t features) const +{ + ENCODE_START(1, 1, bl); + ::encode(name, bl); + ::encode(public_addr, bl, features); + ENCODE_FINISH(bl); +} + +void mon_info_t::decode(bufferlist::iterator& p) +{ + DECODE_START(1, p); + ::decode(name, p); + ::decode(public_addr, p); + DECODE_FINISH(p); +} + +void mon_info_t::print(ostream& out) const +{ + out << "mon." << name + << " public " << public_addr; +} + void MonMap::encode(bufferlist& blist, uint64_t con_features) const { + /* we keep the mon_addr map when encoding to ensure compatibility + * with clients and other monitors that do not yet support the 'mons' + * map. This map keeps its original behavior, containing a mapping of + * monitor id (i.e., 'foo' in 'mon.foo') to the monitor's public + * address -- which is obtained from the public address of each entry + * in the 'mons' map. + */ + map mon_addr; + for (map::const_iterator p = mon_info.begin(); + p != mon_info.end(); + ++p) { + mon_addr[p->first] = p->second.public_addr; + } + if ((con_features & CEPH_FEATURE_MONNAMES) == 0) { __u16 v = 1; ::encode(v, blist); @@ -44,7 +80,7 @@ void MonMap::encode(bufferlist& blist, uint64_t con_features) const ::encode(created, blist); } - ENCODE_START(4, 3, blist); + ENCODE_START(5, 3, blist); ::encode_raw(fsid, blist); ::encode(epoch, blist); ::encode(mon_addr, blist, con_features); @@ -52,12 +88,15 @@ void MonMap::encode(bufferlist& blist, uint64_t con_features) const ::encode(created, blist); ::encode(persistent_features, blist); ::encode(optional_features, blist); + // this superseeds 'mon_addr' + ::encode(mon_info, blist, con_features); ENCODE_FINISH(blist); } void MonMap::decode(bufferlist::iterator &p) { - DECODE_START_LEGACY_COMPAT_LEN_16(4, 3, 3, p); + map mon_addr; + DECODE_START_LEGACY_COMPAT_LEN_16(5, 3, 3, p); ::decode_raw(fsid, p); ::decode(epoch, p); if (struct_v == 1) { @@ -79,8 +118,11 @@ void MonMap::decode(bufferlist::iterator &p) ::decode(persistent_features, p); ::decode(optional_features, p); } - + if (struct_v >= 5) { + ::decode(mon_info, p); + } DECODE_FINISH(p); + sanitize_mons(mon_addr); calc_ranks(); } @@ -119,8 +161,21 @@ int MonMap::read(const char *fn) void MonMap::print_summary(ostream& out) const { out << "e" << epoch << ": " - << mon_addr.size() << " mons at " - << mon_addr; + << mon_info.size() << " mons at {"; + // the map that we used to print, as it was, no longer + // maps strings to the monitor's public address, but to + // mon_info_t instead. As such, print the map in a way + // that keeps the expected format. + bool has_printed = false; + for (map::const_iterator p = mon_info.begin(); + p != mon_info.end(); + ++p) { + if (has_printed) + out << ","; + out << p->first << "=" << p->second.public_addr; + has_printed = true; + } + out << "}"; } void MonMap::print(ostream& out) const @@ -130,10 +185,11 @@ void MonMap::print(ostream& out) const out << "last_changed " << last_changed << "\n"; out << "created " << created << "\n"; unsigned i = 0; - for (map::const_iterator p = addr_name.begin(); - p != addr_name.end(); - ++p) - out << i++ << ": " << p->first << " mon." << p->second << "\n"; + for (vector::const_iterator p = ranks.begin(); + p != ranks.end(); + ++p) { + out << i++ << ": " << get_addr(*p) << " mon." << *p << "\n"; + } } void MonMap::dump(Formatter *f) const @@ -148,13 +204,14 @@ void MonMap::dump(Formatter *f) const f->close_section(); f->open_array_section("mons"); int i = 0; - for (map::const_iterator p = addr_name.begin(); - p != addr_name.end(); + for (vector::const_iterator p = ranks.begin(); + p != ranks.end(); ++p, ++i) { f->open_object_section("mon"); f->dump_int("rank", i); - f->dump_string("name", p->second); - f->dump_stream("addr") << p->first; + f->dump_string("name", *p); + f->dump_stream("addr") << get_addr(*p); + f->dump_stream("public_addr") << get_addr(*p); f->close_section(); } f->close_section(); diff --git a/src/mon/MonMap.h b/src/mon/MonMap.h index 3f1150450ad..51495608089 100644 --- a/src/mon/MonMap.h +++ b/src/mon/MonMap.h @@ -25,18 +25,50 @@ namespace ceph { class Formatter; } +struct mon_info_t { + /** + * monitor name + * + * i.e., 'foo' in 'mon.foo' + */ + string name; + /** + * monitor's public address + * + * public facing address, traditionally used to communicate with all clients + * and other monitors. + */ + entity_addr_t public_addr; + + mon_info_t(string &n, entity_addr_t& p_addr) + : name(n), public_addr(p_addr) + { } + + mon_info_t() { } + + + void encode(bufferlist& bl, uint64_t features) const; + void decode(bufferlist::iterator& p); + void print(ostream& out) const; +}; +WRITE_CLASS_ENCODER_FEATURES(mon_info_t) + +inline ostream& operator<<(ostream& out, const mon_info_t& mon) { + mon.print(out); + return out; +} class MonMap { public: epoch_t epoch; // what epoch/version of the monmap uuid_d fsid; - map mon_addr; utime_t last_changed; utime_t created; - map addr_name; - vector rank_name; - vector rank_addr; + map mon_info; + map addr_mons; + + vector ranks; /** * Persistent Features are all those features that once set on a @@ -73,22 +105,86 @@ class MonMap { return (persistent_features | optional_features); } + void sanitize_mons(map& o) { + + // if mon_info is populated, it means we decoded a map encoded + // by someone who understands the new format (i.e., is able to + // encode 'mon_info'). This means they must also have provided + // a properly populated 'mon_addr' (which we have dropped with + // this patch), 'o' being the contents of said map. In this + // case, 'o' must have the same number of entries as 'mon_info'. + // + // Also, for each entry in 'o', there has to be a matching + // 'mon_info' entry, properly populated with a name and a matching + // 'public_addr'. + // + // OTOH, if 'mon_info' is not populated, it means the one that + // originally encoded the map does not know the new format, and + // 'o' will be our only source of info about the monitors in the + // cluster -- and we will use it to populate our 'mon_info' map. + + bool has_mon_info = false; + if (mon_info.size() > 0) { + assert(o.size() == mon_info.size()); + has_mon_info = true; + } + + for (map::const_iterator p = o.begin(); + p != o.end(); + ++p) { + + // make sure the info we have is accurate + if (has_mon_info) { + assert(mon_info.count(p->first)); + assert(mon_info[p->first].name == p->first); + assert(mon_info[p->first].public_addr == p->second); + continue; + } + + mon_info_t &m = mon_info[p->first]; + m.name = p->first; + m.public_addr = p->second; + } + } + void calc_ranks() { - rank_name.resize(mon_addr.size()); - rank_addr.resize(mon_addr.size()); - addr_name.clear(); - for (map::iterator p = mon_addr.begin(); - p != mon_addr.end(); - ++p) { - assert(addr_name.count(p->second) == 0); - addr_name[p->second] = p->first; + + ranks.resize(mon_info.size()); + addr_mons.clear(); + + // Used to order entries according to public_addr, because that's + // how the ranks are expected to be ordered by. We may expand this + // later on, according to some other criteria, by specifying a + // different comparator. + // + // Please note that we use a 'set' here instead of resorting to + // std::sort() because we need more info than that's available in + // the vector. The vector will thus be ordered by, e.g., public_addr + // while only containing the names of each individual monitor. + // The only way of achieving this with std::sort() would be to first + // insert every mon_info_t entry into a vector 'foo', std::sort() 'foo' + // with custom comparison functions, and then copy each invidual entry + // to a new vector. Unless there's a simpler way, we don't think the + // added complexity makes up for the additional memory usage of a 'set'. + set tmp; + + for (map::iterator p = mon_info.begin(); + p != mon_info.end(); + ++p) { + mon_info_t &m = p->second; + tmp.insert(m); + + // populate addr_mons + assert(addr_mons.count(m.public_addr) == 0); + addr_mons[m.public_addr] = m.name; } + + // map the set to the actual ranks etc unsigned i = 0; - for (map::iterator p = addr_name.begin(); - p != addr_name.end(); - ++p, i++) { - rank_name[i] = p->second; - rank_addr[i] = p->first; + for (set::iterator p = tmp.begin(); + p != tmp.end(); + ++p, ++i) { + ranks[i] = p->name; } } @@ -99,112 +195,150 @@ class MonMap { uuid_d& get_fsid() { return fsid; } - unsigned size() { - return mon_addr.size(); + unsigned size() const { + return mon_info.size(); } - epoch_t get_epoch() { return epoch; } + epoch_t get_epoch() const { return epoch; } void set_epoch(epoch_t e) { epoch = e; } + /** + * Obtain list of public facing addresses + * + * @param ls list to populate with the monitors' addresses + */ void list_addrs(list& ls) const { - for (map::const_iterator p = mon_addr.begin(); - p != mon_addr.end(); - ++p) - ls.push_back(p->second); + for (map::const_iterator p = mon_info.begin(); + p != mon_info.end(); + ++p) { + ls.push_back(p->second.public_addr); + } } + /** + * Add new monitor to the monmap + * + * @param name Monitor name (i.e., 'foo' in 'mon.foo') + * @param addr Monitor's public address + */ void add(const string &name, const entity_addr_t &addr) { - assert(mon_addr.count(name) == 0); - assert(addr_name.count(addr) == 0); - mon_addr[name] = addr; + assert(mon_info.count(name) == 0); + assert(addr_mons.count(addr) == 0); + mon_info_t &m = mon_info[name]; + m.name = name; + m.public_addr = addr; calc_ranks(); } - + + /** + * Remove monitor from the monmap + * + * @param name Monitor name (i.e., 'foo' in 'mon.foo') + */ void remove(const string &name) { - assert(mon_addr.count(name)); - mon_addr.erase(name); + assert(mon_info.count(name)); + mon_info.erase(name); + assert(mon_info.count(name) == 0); calc_ranks(); } + /** + * Rename monitor from @p oldname to @p newname + * + * @param oldname monitor's current name (i.e., 'foo' in 'mon.foo') + * @param newname monitor's new name (i.e., 'bar' in 'mon.bar') + */ void rename(string oldname, string newname) { assert(contains(oldname)); assert(!contains(newname)); - mon_addr[newname] = mon_addr[oldname]; - mon_addr.erase(oldname); + mon_info[newname] = mon_info[oldname]; + mon_info.erase(oldname); + mon_info[newname].name = newname; calc_ranks(); } - bool contains(const string& name) { - return mon_addr.count(name); + bool contains(const string& name) const { + return mon_info.count(name); } - bool contains(const entity_addr_t &a) { - for (map::iterator p = mon_addr.begin(); - p != mon_addr.end(); - ++p) { - if (p->second == a) - return true; + /** + * Check if monmap contains a monitor with address @p a + * + * @note checks for all addresses a monitor may have, public or otherwise. + * + * @param a monitor address + * @returns true if monmap contains a monitor with address @p; + * false otherwise. + */ + bool contains(const entity_addr_t &a) const { + for (map::const_iterator p = mon_info.begin(); + p != mon_info.end(); + ++p) { + if (p->second.public_addr == a) + return true; } return false; } string get_name(unsigned n) const { - assert(n < rank_name.size()); - return rank_name[n]; + assert(n < ranks.size()); + return ranks[n]; } string get_name(const entity_addr_t& a) const { - map::const_iterator p = addr_name.find(a); - if (p == addr_name.end()) + map::const_iterator p = addr_mons.find(a); + if (p == addr_mons.end()) return string(); else return p->second; } int get_rank(const string& n) { - for (unsigned i=0; i::const_iterator p = mon_info.find(n); + return p->second.public_addr; } - const entity_addr_t& get_addr(unsigned m) { - assert(m < rank_addr.size()); - return rank_addr[m]; + const entity_addr_t& get_addr(unsigned m) const { + assert(m < ranks.size()); + return get_addr(ranks[m]); } void set_addr(const string& n, const entity_addr_t& a) { - assert(mon_addr.count(n)); - mon_addr[n] = a; + assert(mon_info.count(n)); + mon_info[n].public_addr = a; calc_ranks(); } entity_inst_t get_inst(const string& n) { - assert(mon_addr.count(n)); + assert(mon_info.count(n)); int m = get_rank(n); assert(m >= 0); // vector can't take negative indicies - entity_inst_t i; - i.addr = rank_addr[m]; - i.name = entity_name_t::MON(m); - return i; + return get_inst(m); } entity_inst_t get_inst(unsigned m) const { - assert(m < rank_addr.size()); + assert(m < ranks.size()); entity_inst_t i; - i.addr = rank_addr[m]; + i.addr = get_addr(m); i.name = entity_name_t::MON(m); return i; } @@ -273,6 +407,15 @@ class MonMap { void dump(ceph::Formatter *f) const; static void generate_test_instances(list& o); + +private: + struct rank_cmp { + bool operator()(const mon_info_t &a, const mon_info_t &b) const { + if (a.public_addr == b.public_addr) + return a.name < b.name; + return a.public_addr < b.public_addr; + } + }; }; WRITE_CLASS_ENCODER_FEATURES(MonMap) -- 2.39.5