From: Sage Weil Date: Fri, 15 Jun 2018 15:53:51 +0000 (-0500) Subject: ceph-objectstore-tool: prevent import of pg that has since merged X-Git-Tag: v14.0.1~371^2~13 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6bd682f53dfe0b2f7c31b5c1ba081afb72f1dd6c;p=ceph.git ceph-objectstore-tool: prevent import of pg that has since merged We currently import a portion of the PG if it has split. Merge is more complicated, though, mainly because COT is operating in a mode where it fast-forwards the PG to the latest OSDMap epoch, which means it has to implement any transformations to the PG (split/merge) independently. Avoid doing this for merge. Signed-off-by: Sage Weil --- diff --git a/qa/tasks/ceph_manager.py b/qa/tasks/ceph_manager.py index 77ad9d4625815..5dd4e7f9e0b43 100644 --- a/qa/tasks/ceph_manager.py +++ b/qa/tasks/ceph_manager.py @@ -334,6 +334,12 @@ class Thrasher: elif proc.exitstatus == 11: self.log("Attempt to import an incompatible export" "...ignored") + elif proc.exitstatus == 12: + # this should be safe to ignore because we only ever move 1 + # copy of the pg at a time, and merge is only initiated when + # all replicas are peered and happy. /me crosses fingers + self.log("PG merged on target" + "...ignored") elif proc.exitstatus: raise Exception("ceph-objectstore-tool: " "import failure with status {ret}". diff --git a/src/tools/ceph_objectstore_tool.cc b/src/tools/ceph_objectstore_tool.cc index 7a1b511f0bda1..3125facf415b5 100644 --- a/src/tools/ceph_objectstore_tool.cc +++ b/src/tools/ceph_objectstore_tool.cc @@ -848,6 +848,20 @@ int get_osdmap(ObjectStore *store, epoch_t e, OSDMap &osdmap, bufferlist& bl) return 0; } +int get_pg_num_history(ObjectStore *store, pool_pg_num_history_t *h) +{ + ObjectStore::CollectionHandle ch = store->open_collection(coll_t::meta()); + bufferlist bl; + auto pghist = OSD::make_pg_num_history_oid(); + int r = store->read(ch, pghist, 0, 0, bl, 0); + if (r >= 0 && bl.length() > 0) { + auto p = bl.cbegin(); + decode(*h, p); + } + cout << __func__ << " pg_num_history " << *h << std::endl; + return 0; +} + int add_osdmap(ObjectStore *store, metadata_section &ms) { return get_osdmap(store, ms.map_epoch, ms.osdmap, ms.osdmap_bl); @@ -1804,6 +1818,16 @@ int ObjectStoreTool::do_import(ObjectStore *store, OSDSuperblock& sb, return 10; // Positive return means exit status } + const pg_pool_t *pi = curmap.get_pg_pool(pgid.pgid.m_pool); + if (pi->get_pg_num() <= pgid.pgid.m_seed) { + cerr << "PG " << pgid.pgid << " no longer exists" << std::endl; + // Special exit code for this error, used by test code + return 12; // Positive return means exit status + } + + pool_pg_num_history_t pg_num_history; + get_pg_num_history(store, &pg_num_history); + ghobject_t pgmeta_oid = pgid.make_pgmeta_oid(); //Check for PG already present. @@ -1814,20 +1838,6 @@ int ObjectStoreTool::do_import(ObjectStore *store, OSDSuperblock& sb, } ObjectStore::CollectionHandle ch; - if (!dry_run) { - ObjectStore::Transaction t; - ch = store->create_new_collection(coll); - PG::_create(t, pgid, - pgid.get_split_bits(curmap.get_pg_pool(pgid.pool())->get_pg_num())); - PG::_init(t, pgid, NULL); - - // mark this coll for removal until we're done - map values; - encode((char)1, values["_remove"]); - t.omap_setkeys(coll, pgid.make_pgmeta_oid(), values); - - store->queue_transaction(ch, std::move(t)); - } OSDriver driver( store, @@ -1858,6 +1868,7 @@ int ObjectStoreTool::do_import(ObjectStore *store, OSDSuperblock& sb, } switch(type) { case TYPE_OBJECT_BEGIN: + ceph_assert(found_metadata); ret = get_object(store, driver, mapper, coll, ebl, curmap, &skipped_objects); if (ret) return ret; break; @@ -1865,8 +1876,51 @@ int ObjectStoreTool::do_import(ObjectStore *store, OSDSuperblock& sb, ret = get_pg_metadata(store, ebl, ms, sb, curmap, pgid); if (ret) return ret; found_metadata = true; + + // make sure there are no conflicting merges + { + auto p = pg_num_history.pg_nums.find(pgid.pgid.m_pool); + if (p != pg_num_history.pg_nums.end()) { + unsigned pg_num = ms.osdmap.get_pg_num(pgid.pgid.m_pool); + for (auto q = p->second.lower_bound(ms.map_epoch); + q != p->second.end(); + ++q) { + pg_t parent; + if (pgid.pgid.is_merge_source(pg_num, q->second, &parent)) { + cerr << "PG " << pgid.pgid << " merge source in epoch " + << q->first << " pg_num " << pg_num + << " -> " << q->second << std::endl; + return 12; + } + if (pgid.pgid.is_merge_target(pg_num, q->second)) { + cerr << "PG " << pgid.pgid << " merge target in epoch " + << q->first << " pg_num " << pg_num + << " -> " << q->second << std::endl; + return 12; + } + pg_num = q->second; + } + } + } + + if (!dry_run) { + ObjectStore::Transaction t; + ch = store->create_new_collection(coll); + PG::_create(t, pgid, + pgid.get_split_bits(curmap.get_pg_pool(pgid.pool())->get_pg_num())); + PG::_init(t, pgid, NULL); + + // mark this coll for removal until we're done + map values; + encode((char)1, values["_remove"]); + t.omap_setkeys(coll, pgid.make_pgmeta_oid(), values); + + store->queue_transaction(ch, std::move(t)); + } + break; case TYPE_PG_END: + ceph_assert(found_metadata); done = true; break; default: