class ObjectDesc {
public:
- ObjectDesc(ContentsGenerator *cont_gen) :
- exists(false), tmap(false), version(0), layers(), cont_gen(cont_gen) {};
- ObjectDesc(const ContDesc &init, ContentsGenerator *cont_gen) :
- exists(false), tmap(false), version(0), layers(), cont_gen(cont_gen) {
+ ObjectDesc(ContentsGenerator *cont_gen)
+ : exists(false), tmap(false), dirty(false),
+ version(0), layers(), cont_gen(cont_gen) {}
+ ObjectDesc(const ContDesc &init, ContentsGenerator *cont_gen)
+ : exists(false), tmap(false), dirty(false),
+ version(0), layers(), cont_gen(cont_gen) {
layers.push_front(init);
- };
+ }
class iterator {
public:
bufferlist header;
bool exists;
bool tmap;
+ bool dirty;
bufferlist tmap_contents;
uint64_t version;
private:
TEST_OP_TMAPPUT,
TEST_OP_WATCH,
TEST_OP_COPY_FROM,
- TEST_OP_HIT_SET_LIST
+ TEST_OP_HIT_SET_LIST,
+ TEST_OP_UNDIRTY,
+ TEST_OP_IS_DIRTY
};
class TestWatchContext : public librados::WatchCtx {
pool_obj_cont[current_snap].insert(pair<string,ObjectDesc>(oid, contents));
}
- void update_object_version(const string &oid, uint64_t version)
+ void update_object_version(const string &oid, uint64_t version,
+ bool dirty = true)
{
for (map<int, map<string,ObjectDesc> >::reverse_iterator i =
pool_obj_cont.rbegin();
map<string,ObjectDesc>::iterator j = i->second.find(oid);
if (j != i->second.end()) {
j->second.version = version;
- cout << __func__ << " oid " << oid << " v " << version << " " << j->second.most_recent() << std::endl;
+ j->second.dirty = dirty;
+ cout << __func__ << " oid " << oid
+ << " v " << version << " " << j->second.most_recent()
+ << " " << (dirty ? "dirty" : "clean")
+ << std::endl;
break;
}
}
}
};
+class UndirtyOp : public TestOp {
+public:
+ librados::AioCompletion *completion;
+ librados::ObjectWriteOperation op;
+ string oid;
+
+ UndirtyOp(int n,
+ RadosTestContext *context,
+ const string &oid,
+ TestOpStat *stat = 0)
+ : TestOp(n, context, stat),
+ completion(NULL),
+ oid(oid)
+ {}
+
+ void _begin()
+ {
+ context->state_lock.Lock();
+ pair<TestOp*, TestOp::CallbackInfo*> *cb_arg =
+ new pair<TestOp*, TestOp::CallbackInfo*>(this,
+ new TestOp::CallbackInfo(0));
+ completion = context->rados.aio_create_completion((void *) cb_arg,
+ &write_callback, 0);
+
+ context->oid_in_use.insert(oid);
+ context->oid_not_in_use.erase(oid);
+ context->state_lock.Unlock();
+
+ op.undirty();
+ int r = context->io_ctx.aio_operate(context->prefix+oid, completion,
+ &op, 0);
+ assert(!r);
+ }
+
+ void _finish(CallbackInfo *info)
+ {
+ context->state_lock.Lock();
+ assert(!done);
+ assert(completion->is_complete());
+ context->oid_in_use.erase(oid);
+ context->oid_not_in_use.insert(oid);
+ context->update_object_version(oid, completion->get_version64(), false);
+ context->kick();
+ done = true;
+ context->state_lock.Unlock();
+ }
+
+ bool finished()
+ {
+ return done;
+ }
+
+ string getType()
+ {
+ return "UndirtyOp";
+ }
+};
+
+class IsDirtyOp : public TestOp {
+public:
+ librados::AioCompletion *completion;
+ librados::ObjectReadOperation op;
+ string oid;
+ bool dirty;
+ ObjectDesc old_value;
+
+ IsDirtyOp(int n,
+ RadosTestContext *context,
+ const string &oid,
+ TestOpStat *stat = 0)
+ : TestOp(n, context, stat),
+ completion(NULL),
+ oid(oid),
+ dirty(false),
+ old_value(&context->cont_gen)
+ {}
+
+ void _begin()
+ {
+ context->state_lock.Lock();
+
+ assert(context->find_object(oid, &old_value)); // FIXME snap?
+
+ pair<TestOp*, TestOp::CallbackInfo*> *cb_arg =
+ new pair<TestOp*, TestOp::CallbackInfo*>(this,
+ new TestOp::CallbackInfo(0));
+ completion = context->rados.aio_create_completion((void *) cb_arg,
+ &write_callback, 0);
+
+ context->oid_in_use.insert(oid);
+ context->oid_not_in_use.erase(oid);
+ context->state_lock.Unlock();
+
+ op.is_dirty(&dirty, NULL);
+ int r = context->io_ctx.aio_operate(context->prefix+oid, completion,
+ &op, 0);
+ assert(!r);
+ }
+
+ void _finish(CallbackInfo *info)
+ {
+ context->state_lock.Lock();
+ assert(!done);
+ assert(completion->is_complete());
+ context->oid_in_use.erase(oid);
+ context->oid_not_in_use.insert(oid);
+
+ int r = completion->get_return_value();
+ if (r == 0) {
+ cout << num << ": " << (dirty ? "dirty" : "clean") << std::endl;
+ assert(old_value.has_contents());
+ assert(dirty == old_value.dirty);
+ } else {
+ cout << num << ": got " << r << std::endl;
+ assert(r == -ENOENT);
+ }
+ context->kick();
+ done = true;
+ context->state_lock.Unlock();
+ }
+
+ bool finished()
+ {
+ return done;
+ }
+
+ string getType()
+ {
+ return "IsDirtyOp";
+ }
+};
+
#endif
return new HitSetListOp(m_op, &context, hash, m_stats);
}
+ case TEST_OP_UNDIRTY:
+ {
+ oid = *(rand_choose(context.oid_not_in_use));
+ cout << "undirty oid " << oid << std::endl;
+ return new UndirtyOp(m_op, &context, oid, m_stats);
+ }
+
+ case TEST_OP_IS_DIRTY:
+ {
+ oid = *(rand_choose(context.oid_not_in_use));
+ cout << "is_dirty oid " << oid << std::endl;
+ return new IsDirtyOp(m_op, &context, oid, m_stats);
+ }
+
default:
cerr << "Invalid op type " << type << std::endl;
assert(0);
{ TEST_OP_WATCH, "watch" },
{ TEST_OP_COPY_FROM, "copy_from" },
{ TEST_OP_HIT_SET_LIST, "hit_set_list" },
+ { TEST_OP_IS_DIRTY, "is_dirty" },
+ { TEST_OP_UNDIRTY, "undirty" },
{ TEST_OP_READ /* grr */, NULL },
};