const bool no_sparse;
bool pool_snaps;
bool write_fadvise_dontneed;
+ string low_tier_pool_name;
+ librados::IoCtx low_tier_io_ctx;
int snapname_num;
map<string,string > redirect_objs;
bool no_sparse,
bool pool_snaps,
bool write_fadvise_dontneed,
+ const string &low_tier_pool_name,
const char *id = 0) :
state_lock("Context Lock"),
pool_obj_cont(),
no_sparse(no_sparse),
pool_snaps(pool_snaps),
write_fadvise_dontneed(write_fadvise_dontneed),
+ low_tier_pool_name(low_tier_pool_name),
snapname_num(0)
{
}
rados.shutdown();
return r;
}
+ if (!low_tier_pool_name.empty()) {
+ r = rados.ioctx_create(low_tier_pool_name.c_str(), low_tier_io_ctx);
+ if (r < 0) {
+ rados.shutdown();
+ return r;
+ }
+ }
bufferlist inbl;
r = rados.mon_command(
"{\"prefix\": \"osd pool set\", \"pool\": \"" + pool_name +
}
};
+class CopyOp : public TestOp {
+public:
+ string oid, oid_src, tgt_pool_name;
+ librados::ObjectWriteOperation op;
+ librados::ObjectReadOperation rd_op;
+ librados::AioCompletion *comp;
+ ObjectDesc src_value, tgt_value;
+ int done;
+ int r;
+ CopyOp(int n,
+ RadosTestContext *context,
+ const string &oid_src,
+ const string &oid,
+ const string &tgt_pool_name,
+ TestOpStat *stat = 0)
+ : TestOp(n, context, stat),
+ oid(oid), oid_src(oid_src), 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_src);
+ context->oid_not_in_use.erase(oid_src);
+
+ string src = context->prefix+oid_src;
+ context->find_object(oid_src, &src_value);
+ op.copy_from(src.c_str(), context->io_ctx, src_value.version);
+
+ cout << "copy op oid " << oid_src << " to " << oid << " tgt_pool_name " << tgt_pool_name << std::endl;
+
+ pair<TestOp*, TestOp::CallbackInfo*> *cb_arg =
+ new pair<TestOp*, TestOp::CallbackInfo*>(this,
+ new TestOp::CallbackInfo(0));
+ comp = context->rados.aio_create_completion((void*) cb_arg, NULL,
+ &write_callback);
+ if (tgt_pool_name == context->low_tier_pool_name) {
+ context->low_tier_io_ctx.aio_operate(context->prefix+oid, comp, &op);
+ } else {
+ context->io_ctx.aio_operate(context->prefix+oid, comp, &op);
+ }
+ }
+
+ void _finish(CallbackInfo *info) override
+ {
+ Mutex::Locker l(context->state_lock);
+
+ if (info->id == 0) {
+ assert(comp->is_complete());
+ cout << num << ": finishing copy op to oid " << oid << std::endl;
+ if ((r = comp->get_return_value())) {
+ cerr << "Error: oid " << oid << " write returned error code "
+ << r << std::endl;
+ ceph_abort();
+ }
+ }
+
+ if (++done == 1) {
+ context->oid_in_use.erase(oid_src);
+ context->oid_not_in_use.insert(oid_src);
+ context->kick();
+ }
+ }
+
+ bool finished() override
+ {
+ return done == 1;
+ }
+
+ string getType() override
+ {
+ return "CopyOp";
+ }
+};
+
class SetChunkOp : public TestOp {
public:
string oid, oid_tgt, tgt_pool_name;
m_total_weight));
}
if (m_set_redirect || m_set_chunk) {
- m_redirect_objects = objects*2; // for creating objects using copy_from
- m_initial_redirected_objects = objects; // for rediect or set-chunk
- // we need pre-initialization process before run the test
- // so, m_ops is increased
if (m_set_redirect) {
- m_ops = ops+m_redirect_objects+m_initial_redirected_objects;
+ m_ops = ops+m_objects+m_objects;
} else {
/* create 10 chunks per an object*/
- m_ops = ops+m_redirect_objects+m_initial_redirected_objects+m_objects*10;
+ m_ops = ops+m_objects+m_objects*10;
}
}
}
TestOp *retval = NULL;
++m_op;
- if (m_op <= m_objects) {
+ if (m_op <= m_objects && !m_set_redirect && !m_set_chunk ) {
stringstream oid;
oid << m_op;
if (m_op % 2) {
}
if (m_set_redirect || m_set_chunk) {
- if (pre_init_extensible_tier(context, retval)) {
+ if (init_extensible_tier(context, retval)) {
return retval;
}
}
}
return retval;
}
-
- bool pre_init_extensible_tier(RadosTestContext &context, TestOp *& op) {
+
+ bool init_extensible_tier(RadosTestContext &context, TestOp *& op) {
/*
- * set-redirect or set-chunk test
- * 0. create default objects
- * 1. create target objects (using copy from)
- * 2. set-redirect or set-chunk
+ * set-redirect or set-chunk test (manifest test)
+ * 0. make default objects (using create op)
+ * 1. set-redirect or set-chunk
+ * 2. initialize target objects (using write op)
* 3. wait for set-* completion
*/
- int create_objects_end = m_objects + m_redirect_objects;
- int set_redirect_end = create_objects_end + m_initial_redirected_objects;
+ int copy_manifest_end = m_objects*2;
+ int make_manifest_end = copy_manifest_end;
if (m_set_chunk) {
- /* create 10 chunks per an object*/
- set_redirect_end += set_redirect_end + m_objects * 10;
+ /* make 10 chunks per an object*/
+ make_manifest_end = make_manifest_end + m_objects * 10;
+ } else {
+ /* redirect */
+ make_manifest_end = make_manifest_end + m_objects;
}
- if (m_op <= create_objects_end) {
+ if (m_op <= m_objects) {
stringstream oid;
- int _oid = m_op;
- oid << _oid;
- if ((_oid) % 2) {
+ oid << m_op;
+ if (m_op % 2) {
oid << " " << string(300, 'o');
}
- stringstream oid2;
- int _oid2 = _oid - m_objects;
- oid2 << _oid2;
- if ((_oid2) % 2) {
- oid2 << " " << string(300, 'o');
+ cout << m_op << ": write initial oid " << oid.str() << std::endl;
+ context.oid_not_flushing.insert(oid.str());
+ if (m_ec_pool) {
+ op = new WriteOp(m_op, &context, oid.str(), true, true);
+ } else {
+ op = new WriteOp(m_op, &context, oid.str(), false, true);
}
- cout << m_op << ": " << "(create target oid) copy_from oid " << oid.str()
- << " from oid " << oid2.str() << std::endl;
- op = new CopyFromOp(m_op, &context, oid.str(), oid2.str(), m_stats);
return true;
- } else if (m_op <= set_redirect_end) {
+ } else if (m_op <= copy_manifest_end) {
+ stringstream oid, oid2;
+ int _oid = m_op-m_objects;
+ oid << _oid;
+ if ((_oid) % 2) {
+ oid << " " << string(300, 'o');
+ }
+ oid2 << _oid << " " << context.low_tier_pool_name;
+ if ((_oid) % 2) {
+ oid2 << " " << string(300, 'm');
+ }
+ cout << m_op << ": " << "copy oid " << oid.str() << " target oid "
+ << oid2.str() << std::endl;
+ op = new CopyOp(m_op, &context, oid.str(), oid2.str(), context.low_tier_pool_name);
+ return true;
+ } else if (m_op <= make_manifest_end) {
if (m_set_redirect) {
- stringstream oid;
- int _oid = m_op-create_objects_end;
+ stringstream oid, oid2;
+ int _oid = m_op-copy_manifest_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');
+ oid2 << _oid << " " << context.low_tier_pool_name;
+ if ((_oid) % 2) {
+ oid2 << " " << string(300, 'm');
}
cout << m_op << ": " << "set_redirect oid " << oid.str() << " target oid "
<< oid2.str() << std::endl;
return true;
}
stringstream oid2;
- int _oid2 = _oid + m_objects;
- oid2 << _oid2;
- if ((_oid2) % 2) {
- oid2 << " " << string(300, 'o');
+ oid2 << _oid << " " << context.low_tier_pool_name;
+ if ((_oid) % 2) {
+ oid2 << " " << string(300, 'm');
}
- /* make a chunk like source object (random offset, random length) -->
- * target object (random offset)
+ /* make a chunk (random offset, random length -->
+ * target object's random offset)
*/
ObjectDesc contents, contents2;
context.find_object(oid.str(), &contents);
- context.find_object(oid2.str(), &contents2);
uint32_t max_len = contents.most_recent_gen()->get_length(contents.most_recent());
- if (max_len > contents2.most_recent_gen()->get_length(contents2.most_recent())) {
- max_len = contents2.most_recent_gen()->get_length(contents2.most_recent());
- }
uint32_t rand_offset = rand() % max_len;
uint32_t rand_length = rand() % max_len;
rand_offset = rand_offset - (rand_offset % 512);
context.pool_name, rand_tgt_offset, m_stats);
return true;
}
- }
-
- if (!context.oid_redirect_not_in_use.size() && m_op > set_redirect_end) {
+ } else if (m_op == make_manifest_end + 1) {
int set_size = context.oid_not_in_use.size();
- /* wait until redirect or set_chunk completion */
- if (set_size < m_objects + m_redirect_objects) {
+ int set_manifest_size = context.oid_redirect_not_in_use.size();
+ cout << m_op << " oid_not_in_use " << set_size << " oid_redirect_not_in_use " << set_manifest_size << std::endl;
+ /* wait for redirect or set_chunk initialization */
+ if (set_size != m_objects || set_manifest_size != 0) {
op = NULL;
m_op--;
- cout << m_op << " wait completion " << std::endl;
+ cout << m_op << " wait for manifest initialization " << std::endl;
return true;
}
- for (int t_op = m_objects+1; t_op <= create_objects_end; t_op++) {
+ for (int t_op = m_objects+1; t_op <= m_objects*2; t_op++) {
stringstream oid;
- oid << t_op;
+ oid << t_op << " " << context.low_tier_pool_name;
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());
- cout << m_op << ": " << " remove oid " << oid.str() << " from oid_*_use " << std::endl;
- if (t_op > m_objects + m_initial_redirected_objects) {
- context.oid_redirect_not_in_use.insert(oid.str());
+ oid << " " << string(300, 'm');
}
+ context.oid_redirect_not_in_use.insert(oid.str());
}
- cout << m_op << ": " << " oid_not_in_use: " << context.oid_not_in_use.size()
- << " oid_in_use: " << context.oid_in_use.size() << std::endl;
}
+
return false;
}
bool m_balance_reads;
bool m_set_redirect;
bool m_set_chunk;
- int m_redirect_objects{0};
- int m_initial_redirected_objects{0};
};
int main(int argc, char **argv)
map<TestOpType, unsigned int> op_weights;
string pool_name = "rbd";
+ string low_tier_pool_name = "";
bool ec_pool = false;
bool no_omap = false;
bool no_sparse = false;
set_redirect = true;
} else if (strcmp(argv[i], "--set_chunk") == 0) {
set_chunk = true;
+ } else if (strcmp(argv[i], "--low_tier_pool") == 0) {
+ low_tier_pool_name = argv[++i];
} else {
cerr << "unknown arg " << argv[i] << std::endl;
exit(1);
}
}
+ if (set_redirect || set_chunk) {
+ if (low_tier_pool_name == "") {
+ cerr << "low_tier_pool_name is needed" << std::endl;
+ exit(1);
+ }
+ }
+
if (op_weights.empty()) {
cerr << "No operations specified" << std::endl;
exit(1);
no_sparse,
pool_snaps,
write_fadvise_dontneed,
+ low_tier_pool_name,
id);
TestOpStat stats;