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 <sage@redhat.com>
This commit is contained in:
Sage Weil 2018-06-15 10:53:51 -05:00
parent 44de03d5e6
commit 6bd682f53d
2 changed files with 74 additions and 14 deletions

View File

@ -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}".

View File

@ -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<string,bufferlist> 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<string,bufferlist> 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: