From: myoungwon oh Date: Sat, 6 May 2017 04:21:04 +0000 (+0900) Subject: src/test: RadosModel (redirected I/O test, Set/Unset Redirect) X-Git-Tag: v12.1.0~57^2~9^2~2^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d44fd08a97a98e658188cbfbfb9f4fb589fa9fce;p=ceph.git src/test: RadosModel (redirected I/O test, Set/Unset Redirect) Signed-off-by: Myoungwon Oh omwmw@sk.com --- diff --git a/src/test/osd/Object.h b/src/test/osd/Object.h index 85a75a56ca9d..09a59a9ceb5c 100644 --- a/src/test/osd/Object.h +++ b/src/test/osd/Object.h @@ -506,6 +506,7 @@ public: bool dirty; uint64_t version; + std::string redirect_target; private: std::list, ContDesc> > layers; }; diff --git a/src/test/osd/RadosModel.h b/src/test/osd/RadosModel.h index bbec3b0cdec5..ff44fee01e97 100644 --- a/src/test/osd/RadosModel.h +++ b/src/test/osd/RadosModel.h @@ -64,7 +64,9 @@ enum TestOpType { TEST_OP_CACHE_TRY_FLUSH, TEST_OP_CACHE_EVICT, TEST_OP_APPEND, - TEST_OP_APPEND_EXCL + TEST_OP_APPEND_EXCL, + TEST_OP_SET_REDIRECT, + TEST_OP_UNSET_REDIRECT }; class TestWatchContext : public librados::WatchCtx2 { @@ -166,6 +168,8 @@ public: set oid_not_in_use; set oid_flushing; set oid_not_flushing; + set oid_redirect_not_in_use; + set oid_redirect_in_use; SharedPtrRegistry snaps_in_use; int current_snap; string pool_name; @@ -190,6 +194,7 @@ public: bool pool_snaps; bool write_fadvise_dontneed; int snapname_num; + map redirect_objs; RadosTestContext(const string &pool_name, int max_in_flight, @@ -477,6 +482,11 @@ public: return false; } + void update_object_redirect_target(const string &oid, const string &target) + { + redirect_objs[oid] = target; + } + bool object_existed_at(const string &oid, int snap = -1) const { ObjectDesc contents; @@ -1948,6 +1958,224 @@ public: } }; +class SetRedirectOp : public TestOp { +public: + string oid, oid_tgt, tgt_pool_name; + ObjectDesc src_value, tgt_value; + librados::ObjectWriteOperation op; + librados::ObjectReadOperation rd_op; + librados::AioCompletion *comp; + ceph::shared_ptr in_use; + int done; + int r; + SetRedirectOp(int n, + RadosTestContext *context, + const string &oid, + const string &oid_tgt, + const string &tgt_pool_name, + TestOpStat *stat = 0) + : TestOp(n, context, stat), + oid(oid), oid_tgt(oid_tgt), tgt_pool_name(tgt_pool_name), + comp(NULL), done(0), + r(0) + {} + + void _begin() override + { + Mutex::Locker l(context->state_lock); + context->oid_in_use.insert(oid); + context->oid_not_in_use.erase(oid); + context->oid_redirect_in_use.insert(oid_tgt); + context->oid_redirect_not_in_use.erase(oid_tgt); + + context->find_object(oid, &src_value); + if(!context->redirect_objs[oid].empty()) { + /* update target's user_version */ + rd_op.stat(NULL, NULL, NULL); + comp = context->rados.aio_create_completion(); + context->io_ctx.aio_operate(context->prefix+oid_tgt, comp, &rd_op, + librados::OPERATION_ORDER_READS_WRITES, + NULL); + comp->wait_for_safe(); + context->update_object_version(oid_tgt, comp->get_version64()); + comp->release(); + + /* unset redirect target */ + comp = context->rados.aio_create_completion(); + bool present = !src_value.deleted(); + context->remove_object(oid); + op.remove(); + context->io_ctx.aio_operate(context->prefix+oid, comp, &op, + librados::OPERATION_ORDER_READS_WRITES | + librados::OPERATION_IGNORE_REDIRECT); + comp->wait_for_safe(); + if ((r = comp->get_return_value())) { + if (!(r == -ENOENT && !present)) { + cerr << "r is " << r << " while deleting " << oid << " and present is " << present << std::endl; + ceph_abort(); + } + } + comp->release(); + + context->oid_redirect_not_in_use.insert(context->redirect_objs[oid]); + context->oid_redirect_in_use.erase(context->redirect_objs[oid]); + + /* copy_from oid_tgt --> oid */ + comp = context->rados.aio_create_completion(); + context->find_object(oid_tgt, &tgt_value); + string src = context->prefix+oid_tgt; + op.copy_from(src.c_str(), context->io_ctx, tgt_value.version); + context->io_ctx.aio_operate(context->prefix+oid, comp, &op, + librados::OPERATION_ORDER_READS_WRITES); + comp->wait_for_safe(); + if ((r = comp->get_return_value())) { + cerr << "Error: oid " << oid << " copy_from " << oid_tgt << " returned error code " + << r << std::endl; + ceph_abort(); + } + context->update_object_full(oid, tgt_value); + context->update_object_version(oid, comp->get_version64()); + comp->release(); + } + + comp = context->rados.aio_create_completion(); + rd_op.stat(NULL, NULL, NULL); + context->io_ctx.aio_operate(context->prefix+oid, comp, &rd_op, + librados::OPERATION_ORDER_READS_WRITES | + librados::OPERATION_IGNORE_REDIRECT, + NULL); + comp->wait_for_safe(); + if ((r = comp->get_return_value()) && !src_value.deleted()) { + cerr << "Error: oid " << oid << " stat returned error code " + << r << std::endl; + ceph_abort(); + } + context->update_object_version(oid, comp->get_version64()); + comp->release(); + + context->find_object(oid, &src_value); + context->find_object(oid_tgt, &tgt_value); + + if (!src_value.deleted() && !tgt_value.deleted()) + context->update_object_full(oid, tgt_value); + + if (src_value.version != 0 && !src_value.deleted()) + op.assert_version(src_value.version); + op.set_redirect(context->prefix+oid_tgt, context->io_ctx, tgt_value.version); + + pair *cb_arg = + new pair(this, + new TestOp::CallbackInfo(0)); + comp = context->rados.aio_create_completion((void*) cb_arg, NULL, + &write_callback); + context->io_ctx.aio_operate(context->prefix+oid, comp, &op, + librados::OPERATION_ORDER_READS_WRITES); + } + + void _finish(CallbackInfo *info) override + { + Mutex::Locker l(context->state_lock); + + if (info->id == 0) { + assert(comp->is_complete()); + cout << num << ": finishing set_redirect to oid " << oid << std::endl; + if ((r = comp->get_return_value())) { + if (r == -ENOENT && src_value.deleted()) { + cout << num << ": got expected ENOENT (src dne)" << std::endl; + } else { + cerr << "Error: oid " << oid << " set_redirect " << oid_tgt << " returned error code " + << r << std::endl; + ceph_abort(); + } + } else { + context->update_object_redirect_target(oid, oid_tgt); + context->update_object_version(oid, comp->get_version64()); + } + } + + if (++done == 1) { + context->oid_in_use.erase(oid); + context->oid_not_in_use.insert(oid); + context->kick(); + } + } + + bool finished() override + { + return done == 1; + } + + string getType() override + { + return "SetRedirectOp"; + } +}; + +class UnsetRedirectOp : public TestOp { +public: + string oid; + librados::ObjectWriteOperation op; + librados::AioCompletion *completion; + librados::AioCompletion *comp; + + UnsetRedirectOp(int n, + RadosTestContext *context, + const string &oid, + TestOpStat *stat = 0) + : TestOp(n, context, stat), oid(oid) + {} + + void _begin() override + { + context->state_lock.Lock(); + if (context->get_watch_context(oid)) { + context->kick(); + context->state_lock.Unlock(); + return; + } + + ObjectDesc contents; + context->find_object(oid, &contents); + bool present = !contents.deleted(); + + context->oid_in_use.insert(oid); + context->oid_not_in_use.erase(oid); + context->seq_num++; + + context->remove_object(oid); + + context->state_lock.Unlock(); + + comp = context->rados.aio_create_completion(); + op.remove(); + context->io_ctx.aio_operate(context->prefix+oid, comp, &op, + librados::OPERATION_ORDER_READS_WRITES | + librados::OPERATION_IGNORE_REDIRECT); + comp->wait_for_safe(); + int r = comp->get_return_value(); + if (r && !(r == -ENOENT && !present)) { + cerr << "r is " << r << " while deleting " << oid << " and present is " << present << std::endl; + ceph_abort(); + } + + context->state_lock.Lock(); + context->oid_in_use.erase(oid); + context->oid_not_in_use.insert(oid); + if(!context->redirect_objs[oid].empty()) { + context->oid_redirect_not_in_use.insert(context->redirect_objs[oid]); + context->oid_redirect_in_use.erase(context->redirect_objs[oid]); + context->update_object_redirect_target(oid, string()); + } + context->kick(); + context->state_lock.Unlock(); + } + + string getType() override + { + return "UnsetRedirectOp"; + } +}; + class HitSetListOp : public TestOp { librados::AioCompletion *comp1, *comp2; uint32_t hash; diff --git a/src/test/osd/TestRados.cc b/src/test/osd/TestRados.cc index 4a1bf8ef374f..0fb2e776cb4b 100644 --- a/src/test/osd/TestRados.cc +++ b/src/test/osd/TestRados.cc @@ -29,12 +29,14 @@ public: TestOpStat *stats, int max_seconds, bool ec_pool, - bool balance_reads) : + bool balance_reads, + bool set_redirect) : m_nextop(NULL), m_op(0), m_ops(ops), m_seconds(max_seconds), m_objects(objects), m_stats(stats), m_total_weight(0), m_ec_pool(ec_pool), - m_balance_reads(balance_reads) + m_balance_reads(balance_reads), + m_set_redirect(set_redirect) { m_start = time(0); for (map::const_iterator it = op_weights.begin(); @@ -44,6 +46,12 @@ public: m_weight_sums.insert(pair(it->first, m_total_weight)); } + if (m_set_redirect) { + /* create redirect objects + set-redirect*/ + m_redirect_objects = objects*2; // for copy_from + set-redirect test + m_initial_redirected_objects = objects; + m_ops = ops+m_redirect_objects+m_initial_redirected_objects; + } } TestOp *next(RadosTestContext &context) override @@ -68,6 +76,66 @@ public: } else if (m_op >= m_ops) { return NULL; } + + if (m_set_redirect) { + /* + * set-redirect test + * 1. create objects (copy from) + * 2. set-redirect + */ + int create_objects_end = m_objects + m_redirect_objects; + int set_redirect_end = create_objects_end + m_initial_redirected_objects; + + if (m_op <= create_objects_end) { + stringstream oid; + int _oid = m_op; + oid << _oid; + if ((_oid) % 2) { + oid << " " << string(300, 'o'); + } + stringstream oid2; + int _oid2 = _oid - m_objects; + oid2 << _oid2; + if ((_oid2) % 2) { + oid2 << " " << string(300, 'o'); + } + cout << m_op << ": " << "(create redirect oid) copy_from oid " << oid.str() + << " from oid " << oid2.str() << std::endl; + return new CopyFromOp(m_op, &context, oid.str(), oid2.str(), m_stats); + } else if (m_op <= set_redirect_end) { + stringstream oid; + int _oid = m_op-create_objects_end; + oid << _oid; + if ((_oid) % 2) { + oid << " " << string(300, 'o'); + } + stringstream oid2; + int _oid2 = _oid + m_objects; + oid2 << _oid2; + if ((_oid2) % 2) { + oid2 << " " << string(300, 'o'); + } + cout << m_op << ": " << "set_redirect oid " << oid.str() << " target oid " + << oid2.str() << std::endl; + return new SetRedirectOp(m_op, &context, oid.str(), oid2.str(), context.pool_name); + } + + if (!context.oid_redirect_not_in_use.size() && m_op == set_redirect_end+1) { + for (int t_op = m_objects+1; t_op <= create_objects_end; t_op++) { + stringstream oid; + oid << t_op; + if (t_op % 2) { + oid << " " << string(300, 'o'); + } + context.oid_not_flushing.erase(oid.str()); + context.oid_not_in_use.erase(oid.str()); + context.oid_in_use.erase(oid.str()); + if (t_op > m_objects + m_initial_redirected_objects) { + context.oid_redirect_not_in_use.insert(oid.str()); + } + } + } + } if (m_nextop) { retval = m_nextop; @@ -234,6 +302,17 @@ private: << context.current_snap << std::endl; return new WriteOp(m_op, &context, oid, true, true, m_stats); + case TEST_OP_SET_REDIRECT: + oid = *(rand_choose(context.oid_not_in_use)); + oid2 = *(rand_choose(context.oid_redirect_not_in_use)); + cout << m_op << ": " << "set_redirect oid " << oid << " target oid " << oid2 << std::endl; + return new SetRedirectOp(m_op, &context, oid, oid2, context.pool_name, m_stats); + + case TEST_OP_UNSET_REDIRECT: + oid = *(rand_choose(context.oid_not_in_use)); + cout << m_op << ": " << "unset_redirect oid " << oid << std::endl; + return new UnsetRedirectOp(m_op, &context, oid, m_stats); + default: cerr << m_op << ": Invalid op type " << type << std::endl; ceph_abort(); @@ -252,6 +331,9 @@ private: unsigned int m_total_weight; bool m_ec_pool; bool m_balance_reads; + bool m_set_redirect; + int m_redirect_objects; + int m_initial_redirected_objects; }; int main(int argc, char **argv) @@ -290,6 +372,8 @@ int main(int argc, char **argv) { TEST_OP_CACHE_EVICT, "cache_evict", true }, { TEST_OP_APPEND, "append", true }, { TEST_OP_APPEND_EXCL, "append_excl", true }, + { TEST_OP_SET_REDIRECT, "set_redirect", true }, + { TEST_OP_UNSET_REDIRECT, "unset_redirect", true }, { TEST_OP_READ /* grr */, NULL }, }; @@ -299,6 +383,7 @@ int main(int argc, char **argv) bool no_omap = false; bool no_sparse = false; bool balance_reads = false; + bool set_redirect = false; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "--max-ops") == 0) @@ -369,6 +454,8 @@ int main(int argc, char **argv) cout << "adding op weight " << op_types[j].name << " -> " << weight << std::endl; op_weights.insert(pair(op_types[j].op, weight)); } + } else if (strcmp(argv[i], "--set_redirect") == 0) { + set_redirect = true; } else { cerr << "unknown arg " << argv[i] << std::endl; //usage(); @@ -431,7 +518,7 @@ int main(int argc, char **argv) WeightedTestGenerator gen = WeightedTestGenerator( ops, objects, op_weights, &stats, max_seconds, - ec_pool, balance_reads); + ec_pool, balance_reads, set_redirect); int r = context.init(); if (r < 0) { cerr << "Error initializing rados test context: "