This commit extends the object dispatch write function to support RADOS object version assertion.
In addition, we add a write flag which allows to assert that an object exists before writing.
Signed-off-by: Or Ozeri <oro@il.ibm.com>
template <typename I>
bool ObjectCacherObjectDispatch<I>::write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
on_dispatched = util::create_async_context_callback(*m_image_ctx,
on_dispatched);
+ // cache layer does not handle version checking
+ if (assert_version.has_value() ||
+ (write_flags & io::OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE) != 0) {
+ ObjectExtents object_extents;
+ object_extents.emplace_back(data_object_name(m_image_ctx, object_no),
+ object_no, object_off, data.length(), 0);
+
+ *dispatch_result = io::DISPATCH_RESULT_CONTINUE;
+
+ // ensure any in-flight writeback is complete before advancing
+ // the write request
+ std::lock_guard locker{m_cache_lock};
+ m_object_cacher->discard_writeback(m_object_set, object_extents,
+ on_dispatched);
+ return true;
+ }
+
m_image_ctx->image_lock.lock_shared();
ObjectCacher::OSDWrite *wr = m_object_cacher->prepare_write(
snapc, data, ceph::real_time::min(), op_flags, *journal_tid);
bufferlist ws_data;
io::util::assemble_write_same_extent(extent, data, &ws_data, true);
- return write(object_no, object_off, std::move(ws_data), snapc, op_flags,
- parent_trace, object_dispatch_flags, journal_tid,
+ return write(object_no, object_off, std::move(ws_data), snapc, op_flags, 0,
+ std::nullopt, parent_trace, object_dispatch_flags, journal_tid,
dispatch_result, on_finish, on_dispatched);
}
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) override;
auto req = io::ObjectDispatchSpec::create_write(
m_ictx, io::OBJECT_DISPATCH_LAYER_CACHE, object_no, off, std::move(bl_copy),
- snapc, 0, journal_tid, trace, ctx);
+ snapc, 0, 0, std::nullopt, journal_tid, trace, ctx);
req->object_dispatch_flags = (
io::OBJECT_DISPATCH_FLAG_FLUSH |
io::OBJECT_DISPATCH_FLAG_WILL_RETRY_ON_ERROR);
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
template <typename I>
bool WriteAroundObjectDispatch<I>::write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context**on_finish, Context* on_dispatched) {
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context**on_finish, Context* on_dispatched) override;
template <typename I>
bool CryptoObjectDispatch<I>::write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
auto req = io::ObjectDispatchSpec::create_write(
m_image_ctx, io::OBJECT_DISPATCH_LAYER_NONE, object_no,
- object_off, std::move(ws_data), snapc, op_flags, 0,
+ object_off, std::move(ws_data), snapc, op_flags, 0, std::nullopt, 0,
parent_trace, ctx);
req->send();
return true;
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) override;
auto req = ObjectDispatchSpec::create_write(
&image_ctx, OBJECT_DISPATCH_LAYER_NONE, object_extent.object_no,
- object_extent.offset, std::move(bl), snapc, m_op_flags, journal_tid,
- this->m_trace, on_finish);
+ object_extent.offset, std::move(bl), snapc, m_op_flags, 0, std::nullopt,
+ journal_tid, this->m_trace, on_finish);
return req;
}
}
req = ObjectDispatchSpec::create_write(
&image_ctx, OBJECT_DISPATCH_LAYER_NONE, object_extent.object_no,
- object_extent.offset, std::move(bl), snapc, m_op_flags, journal_tid,
- this->m_trace, on_finish);
+ object_extent.offset, std::move(bl), snapc, m_op_flags, 0, std::nullopt,
+ journal_tid, this->m_trace, on_finish);
return req;
}
template <typename I>
bool ObjectDispatch<I>::write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
*dispatch_result = DISPATCH_RESULT_COMPLETE;
auto req = new ObjectWriteRequest<I>(m_image_ctx, object_no, object_off,
std::move(data), snapc, op_flags,
+ write_flags, assert_version,
parent_trace, on_dispatched);
req->send();
return true;
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) override;
virtual bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, DispatchResult* dispatch_result,
Context**on_finish, Context* on_dispatched) = 0;
struct WriteRequest : public WriteRequestBase {
ceph::bufferlist data;
+ int write_flags;
+ std::optional<uint64_t> assert_version;
WriteRequest(uint64_t object_no, uint64_t object_off,
ceph::bufferlist&& data, const ::SnapContext& snapc,
+ int write_flags, std::optional<uint64_t> assert_version,
uint64_t journal_tid)
: WriteRequestBase(object_no, object_off, snapc, journal_tid),
- data(std::move(data)) {
+ data(std::move(data)), write_flags(write_flags),
+ assert_version(assert_version) {
}
};
static ObjectDispatchSpec* create_write(
ImageCtxT* image_ctx, ObjectDispatchLayer object_dispatch_layer,
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags, uint64_t journal_tid,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version, uint64_t journal_tid,
const ZTracer::Trace &parent_trace, Context *on_finish) {
return new ObjectDispatchSpec(image_ctx->io_object_dispatcher,
object_dispatch_layer,
WriteRequest{object_no, object_off,
std::move(data), snapc,
+ write_flags, assert_version,
journal_tid},
op_flags, parent_trace, on_finish);
}
bool operator()(ObjectDispatchSpec::WriteRequest& write) const {
return object_dispatch->write(
write.object_no, write.object_off, std::move(write.data), write.snapc,
- object_dispatch_spec->op_flags, object_dispatch_spec->parent_trace,
+ object_dispatch_spec->op_flags, write.write_flags, write.assert_version,
+ object_dispatch_spec->parent_trace,
&object_dispatch_spec->object_dispatch_flags, &write.journal_tid,
&object_dispatch_spec->dispatch_result,
&object_dispatch_spec->dispatcher_ctx.on_finish,
ObjectRequest<I>*
ObjectRequest<I>::create_write(
I *ictx, uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, Context *completion) {
return new ObjectWriteRequest<I>(ictx, object_no, object_off,
std::move(data), snapc, op_flags,
+ write_flags, assert_version,
parent_trace, completion);
}
template <typename I>
void ObjectWriteRequest<I>::add_write_ops(neorados::WriteOp* wr) {
+ if ((m_write_flags & OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE) != 0) {
+ wr->create(true);
+ } else if (m_assert_version.has_value()) {
+ wr->assert_version(m_assert_version.value());
+ }
if (this->m_full_object) {
wr->write_full(bufferlist{m_write_data});
} else {
static ObjectRequest* create_write(
ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
ceph::bufferlist&& data, const ::SnapContext &snapc, int op_flags,
+ int write_flags, std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, Context *completion);
static ObjectRequest* create_discard(
ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
ObjectWriteRequest(
ImageCtxT *ictx, uint64_t object_no, uint64_t object_off,
ceph::bufferlist&& data, const ::SnapContext &snapc, int op_flags,
+ int write_flags, std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, Context *completion)
: AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off,
data.length(), snapc, "write",
parent_trace, completion),
- m_write_data(std::move(data)), m_op_flags(op_flags) {
+ m_write_data(std::move(data)), m_op_flags(op_flags),
+ m_write_flags(write_flags), m_assert_version(assert_version) {
}
bool is_empty_write_op() const override {
private:
ceph::bufferlist m_write_data;
int m_op_flags;
+ int m_write_flags;
+ std::optional<uint64_t> m_assert_version;
};
template <typename ImageCtxT = ImageCtx>
auto req = ObjectDispatchSpec::create_write(
image_ctx, OBJECT_DISPATCH_LAYER_SCHEDULER,
m_object_no, offset, std::move(merged_requests.data), m_snapc,
- m_op_flags, 0, {}, ctx);
+ m_op_flags, 0, std::nullopt, 0, {}, ctx);
req->object_dispatch_flags = m_object_dispatch_flags;
req->send();
template <typename I>
bool SimpleSchedulerObjectDispatch<I>::write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
ldout(cct, 20) << data_object_name(m_image_ctx, object_no) << " "
<< object_off << "~" << data.length() << dendl;
+ // don't try to batch assert version writes
+ if (assert_version.has_value() ||
+ (write_flags & OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE) != 0) {
+ dispatch_delayed_requests(object_no);
+ return false;
+ }
+
std::lock_guard locker{m_lock};
if (try_delay_write(object_no, object_off, std::move(data), snapc, op_flags,
*object_dispatch_flags, on_dispatched)) {
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) override;
OBJECT_DISPATCH_LAYER_LAST
};
+enum {
+ OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE = 1UL << 0
+};
+
enum {
OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE = 1UL << 0,
OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE = 1UL << 1
template <typename I>
bool ObjectDispatch<I>::write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) {
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* object_dispatch_flags,
uint64_t* journal_tid, io::DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) override;
bufferlist bl;
auto req = new io::ObjectWriteRequest<I>(&image_ctx, m_object_no, 0,
- std::move(bl), m_snapc, 0, {},
- this);
+ std::move(bl), m_snapc, 0, 0,
+ std::nullopt, {}, this);
if (!req->has_parent()) {
// stop early if the parent went away - it just means
// another flatten finished first or the image was resized
if (is_within_overlap_bounds()) {
bufferlist bl;
auto req = new io::ObjectWriteRequest<I>(&image_ctx, m_object_no, 0,
- std::move(bl), m_snapc, 0, {},
- ctx);
+ std::move(bl), m_snapc, 0, 0,
+ std::nullopt, {}, ctx);
ldout(cct, 20) << "copyup object req " << req << ", object_no "
<< m_object_no << dendl;
ASSERT_EQ(mock_parent_image_cache->discard(0, 0, 0, *temp_snapc, 0, *temp_trace, temp_op_flags,
temp_journal_tid, temp_dispatch_result, temp_on_finish, temp_on_dispatched), false);
- ASSERT_EQ(mock_parent_image_cache->write(0, 0, std::move(temp_bl), *temp_snapc, 0,
+ ASSERT_EQ(mock_parent_image_cache->write(0, 0, std::move(temp_bl), *temp_snapc, 0, 0, std::nullopt,
*temp_trace, temp_op_flags, temp_journal_tid, temp_dispatch_result,
temp_on_finish, temp_on_dispatched), false);
ASSERT_EQ(mock_parent_image_cache->write_same(0, 0, 0, std::move(buffer_extents),
MockContext finish_ctx;
MockContext dispatch_ctx;
Context* finish_ctx_ptr = &finish_ctx;
- ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr, &dispatch_ctx));
+ ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr,
+ &dispatch_ctx));
ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
}
MockContext finish_ctx;
MockContext dispatch_ctx;
Context* finish_ctx_ptr = &finish_ctx;
- ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr, &dispatch_ctx));
+ ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr,
+ &dispatch_ctx));
ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
ASSERT_FALSE(object_dispatch.flush(io::FLUSH_SOURCE_USER, {}, nullptr,
expect_context_complete(dispatch_ctx, 0);
expect_context_complete(finish_ctx, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr, &dispatch_ctx));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr,
+ &dispatch_ctx));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr, &finish_ctx);
ASSERT_EQ(0, dispatch_ctx.wait());
expect_context_complete(dispatch_ctx, 0);
expect_context_complete(finish_ctx, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr, &dispatch_ctx));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr,
+ &dispatch_ctx));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr, &finish_ctx);
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt,{}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
expect_context_complete(dispatch_ctx2, 0);
expect_context_complete(finish_ctx2, 0);
- ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr2, &dispatch_ctx2));
+ ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr2,
+ &dispatch_ctx2));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
MockContext dispatch_ctx3;
Context* finish_ctx_ptr3 = &finish_ctx3;
- ASSERT_TRUE(object_dispatch.write(0, 1024, std::move(data), {}, 0,
- {}, nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr3, &dispatch_ctx3));
+ ASSERT_TRUE(object_dispatch.write(0, 1024, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr3,
+ &dispatch_ctx3));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr3, &finish_ctx3);
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
MockContext dispatch_ctx2;
Context* finish_ctx_ptr2 = &finish_ctx2;
- ASSERT_TRUE(object_dispatch.write(0, 8192, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr2, &dispatch_ctx2));
+ ASSERT_TRUE(object_dispatch.write(0, 8192, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr2,
+ &dispatch_ctx2));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
ASSERT_EQ(0, dispatch_ctx1.wait());
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
expect_context_complete(dispatch_ctx2, 0);
expect_context_complete(finish_ctx2, 0);
- ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr2, &dispatch_ctx2));
+ ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr2,
+ &dispatch_ctx2));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
MockContext dispatch_ctx3;
Context* finish_ctx_ptr3 = &finish_ctx3;
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0,
- {}, nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr3, &dispatch_ctx3));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr3,
+ &dispatch_ctx3));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr3, &finish_ctx3);
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
ASSERT_EQ(0, dispatch_ctx1.wait());
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
ASSERT_EQ(0, dispatch_ctx1.wait());
MockContext dispatch_ctx2;
Context* finish_ctx_ptr2 = &finish_ctx2;
- ASSERT_TRUE(object_dispatch.write(0, 8192, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr2, &dispatch_ctx2));
+ ASSERT_TRUE(object_dispatch.write(0, 8192, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr2,
+ &dispatch_ctx2));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
ASSERT_EQ(0, dispatch_ctx1.wait());
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
ASSERT_EQ(0, dispatch_ctx1.wait());
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
ASSERT_EQ(0, dispatch_ctx1.wait());
expect_context_complete(dispatch_ctx1, 0);
expect_context_complete(finish_ctx1, 0);
- ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr1, &dispatch_ctx1));
+ ASSERT_TRUE(object_dispatch.write(0, 0, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr1,
+ &dispatch_ctx1));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr1, &finish_ctx1);
ASSERT_EQ(0, dispatch_ctx1.wait());
MockContext finish_ctx2;
MockContext dispatch_ctx2;
Context* finish_ctx_ptr2 = &finish_ctx2;
- ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr2, &dispatch_ctx2));
+ ASSERT_TRUE(object_dispatch.write(0, 4096, std::move(data), {}, 0, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr2,
+ &dispatch_ctx2));
ASSERT_EQ(io::DISPATCH_RESULT_CONTINUE, dispatch_result);
ASSERT_NE(finish_ctx_ptr2, &finish_ctx2);
MockContext dispatch_ctx;
Context* finish_ctx_ptr = &finish_ctx;
ASSERT_FALSE(object_dispatch.write(0, 0, std::move(data), {},
- LIBRADOS_OP_FLAG_FADVISE_FUA, {},
- nullptr, nullptr, &dispatch_result,
- &finish_ctx_ptr, &dispatch_ctx));
+ LIBRADOS_OP_FLAG_FADVISE_FUA, 0,
+ std::nullopt, {}, nullptr, nullptr,
+ &dispatch_result, &finish_ctx_ptr,
+ &dispatch_ctx));
ASSERT_EQ(finish_ctx_ptr, &finish_ctx);
}
TEST_F(TestMockCryptoCryptoObjectDispatch, Write) {
expect_encrypt();
ASSERT_TRUE(mock_crypto_object_dispatch->write(
- 0, 0, std::move(data), mock_image_ctx->snapc, 0, {}, nullptr, nullptr,
- &dispatch_result, &on_finish, on_dispatched));
+ 0, 0, std::move(data), mock_image_ctx->snapc, 0, 0, std::nullopt, {},
+ nullptr, nullptr, &dispatch_result, &on_finish, on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_CONTINUE);
ASSERT_EQ(on_finish, &finished_cond); // not modified
on_finish->complete(0);
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
+TEST_F(TestMockIoObjectRequest, WriteWithCreateExclusiveFlag) {
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_get_object_size(mock_image_ctx);
+
+ MockExclusiveLock mock_exclusive_lock;
+ if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+ mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+ expect_is_lock_owner(mock_exclusive_lock);
+ }
+
+ MockObjectMap mock_object_map;
+ if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+ mock_image_ctx.object_map = &mock_object_map;
+ }
+
+ // exclusive create should succeed
+ {
+ bufferlist bl;
+ bl.append(std::string(4096, '1'));
+
+ InSequence seq;
+ expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_object_may_exist(mock_image_ctx, 0, true);
+ expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
+ 0);
+ expect_write(mock_image_ctx, 0, 4096, 0);
+
+ C_SaferCond ctx;
+ auto req = MockObjectWriteRequest::create_write(
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0,
+ OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE, std::nullopt, {}, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+ }
+
+ // exclusive create should fail since object already exists
+ {
+ bufferlist bl;
+ bl.append(std::string(4096, '1'));
+
+ InSequence seq;
+ expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_object_may_exist(mock_image_ctx, 0, true);
+ expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
+ 0);
+
+ C_SaferCond ctx;
+ auto req = MockObjectWriteRequest::create_write(
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0,
+ OBJECT_WRITE_FLAG_CREATE_EXCLUSIVE, std::nullopt, {}, &ctx);
+ req->send();
+ ASSERT_EQ(-EEXIST, ctx.wait());
+ }
+}
+
+TEST_F(TestMockIoObjectRequest, WriteWithAssertVersion) {
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+
+ MockTestImageCtx mock_image_ctx(*ictx);
+ expect_get_object_size(mock_image_ctx);
+
+ MockExclusiveLock mock_exclusive_lock;
+ if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
+ mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
+ expect_is_lock_owner(mock_exclusive_lock);
+ }
+
+ MockObjectMap mock_object_map;
+ if (ictx->test_features(RBD_FEATURE_OBJECT_MAP)) {
+ mock_image_ctx.object_map = &mock_object_map;
+ }
+
+ // write an object
+ {
+ bufferlist bl;
+ bl.append(std::string(4096, '1'));
+
+ InSequence seq;
+ expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_object_may_exist(mock_image_ctx, 0, true);
+ expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
+ 0);
+ expect_write(mock_image_ctx, 0, 4096, 0);
+
+ C_SaferCond ctx;
+ auto req = MockObjectWriteRequest::create_write(
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+ }
+
+ // assert version should succeed (version = 1)
+ {
+ bufferlist bl;
+ bl.append(std::string(4096, '1'));
+
+ InSequence seq;
+ expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_object_may_exist(mock_image_ctx, 0, true);
+ expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
+ 0);
+ expect_write(mock_image_ctx, 0, 4096, 0);
+
+ C_SaferCond ctx;
+ auto req = MockObjectWriteRequest::create_write(
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::make_optional(1), {}, &ctx);
+ req->send();
+ ASSERT_EQ(0, ctx.wait());
+ }
+
+ // assert with wrong (lower) version (version = 2)
+ {
+ bufferlist bl;
+ bl.append(std::string(4096, '1'));
+
+ InSequence seq;
+ expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_object_may_exist(mock_image_ctx, 0, true);
+ expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
+ 0);
+
+ C_SaferCond ctx;
+ auto req = MockObjectWriteRequest::create_write(
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::make_optional(1), {}, &ctx);
+ req->send();
+ ASSERT_EQ(-ERANGE, ctx.wait());
+ }
+
+ // assert with wrong (higher) version (version = 2)
+ {
+ bufferlist bl;
+ bl.append(std::string(4096, '1'));
+
+ InSequence seq;
+ expect_get_parent_overlap(mock_image_ctx, CEPH_NOSNAP, 0, 0);
+ expect_object_may_exist(mock_image_ctx, 0, true);
+ expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_EXISTS, {}, false,
+ 0);
+
+ C_SaferCond ctx;
+ auto req = MockObjectWriteRequest::create_write(
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::make_optional(3), {}, &ctx);
+ req->send();
+ ASSERT_EQ(-EOVERFLOW, ctx.wait());
+ }
+}
+
TEST_F(TestMockIoObjectRequest, WriteFull) {
librbd::ImageCtx *ictx;
ASSERT_EQ(0, open_image(m_image_name, &ictx));
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(-EPERM, ctx.wait());
}
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(0, ctx.wait());
}
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(-EPERM, ctx.wait());
}
C_SaferCond ctx;
auto req = MockObjectWriteRequest::create_write(
- &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, {}, &ctx);
+ &mock_image_ctx, 0, 0, std::move(bl), mock_image_ctx.snapc, 0, 0,
+ std::nullopt, {}, &ctx);
req->send();
ASSERT_EQ(-EBLACKLISTED, ctx.wait());
}
C_SaferCond cond;
Context *on_finish = &cond;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, nullptr, &on_finish, nullptr));
ASSERT_NE(on_finish, &cond);
on_finish->complete(0);
C_SaferCond cond1;
Context *on_finish1 = &cond1;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
ASSERT_NE(on_finish1, &cond1);
Context *on_finish2 = &cond2;
C_SaferCond on_dispatched;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
&on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
C_SaferCond cond1;
Context *on_finish1 = &cond1;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
ASSERT_NE(on_finish1, &cond1);
Context *on_finish2 = &cond2;
C_SaferCond on_dispatched;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
&on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
C_SaferCond cond1;
Context *on_finish1 = &cond1;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
ASSERT_NE(on_finish1, &cond1);
Context *on_finish2 = &cond2;
C_SaferCond on_dispatched2;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
&on_dispatched2));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish2, &cond2);
Context *on_finish3 = &cond3;
C_SaferCond on_dispatched3;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish3,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish3,
&on_dispatched3));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish3, &cond3);
Context *on_finish4 = &cond4;
C_SaferCond on_dispatched4;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish4,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {},&object_dispatch_flags, nullptr, &dispatch_result, &on_finish4,
&on_dispatched4));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish4, &cond4);
Context *on_finish5 = &cond5;
C_SaferCond on_dispatched5;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish5,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish5,
&on_dispatched5));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish5, &cond5);
Context *on_finish6 = &cond6;
C_SaferCond on_dispatched6;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish6,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish6,
&on_dispatched6));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish6, &cond6);
C_SaferCond cond1;
Context *on_finish1 = &cond1;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
ASSERT_NE(on_finish1, &cond1);
Context *on_finish2 = &cond2;
C_SaferCond on_dispatched2;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
&on_dispatched2));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish2, &cond2);
C_SaferCond cond3;
Context *on_finish3 = &cond3;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish3, nullptr));
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish3,
+ nullptr));
ASSERT_NE(on_finish3, &cond3);
on_finish1->complete(0);
C_SaferCond cond1;
Context *on_finish1 = &cond1;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
ASSERT_NE(on_finish1, &cond1);
Context *on_finish2 = &cond2;
C_SaferCond on_dispatched2;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
&on_dispatched2));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish2, &cond2);
Context *on_finish3 = &cond3;
C_SaferCond on_dispatched3;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish3,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish3,
&on_dispatched3));
ASSERT_NE(on_finish3, &cond3);
Context *on_finish5 = &cond5;
C_SaferCond on_dispatched5;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish5,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish5,
&on_dispatched5));
ASSERT_NE(on_finish5, &cond5);
ASSERT_NE(timer_task, nullptr);
Context *on_finish7 = &cond7;
C_SaferCond on_dispatched7;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, object_off, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish7,
+ 0, object_off, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish7,
&on_dispatched7));
ASSERT_NE(on_finish7, &cond7);
ASSERT_NE(timer_task, nullptr);
C_SaferCond cond1;
Context *on_finish1 = &cond1;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- object_no, 0, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
+ object_no, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
ASSERT_NE(on_finish1, &cond1);
Context *timer_task = nullptr;
Context *on_finish2 = &cond2;
C_SaferCond on_dispatched2;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- object_no, 0, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
+ object_no, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
&on_dispatched2));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish2, &cond2);
C_SaferCond cond3;
Context *on_finish3 = &cond3;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- object_no, 0, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, nullptr, &on_finish3, nullptr));
+ object_no, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, nullptr, &on_finish3, nullptr));
ASSERT_NE(on_finish3, &cond3);
data.clear();
Context *on_finish4 = &cond4;
C_SaferCond on_dispatched4;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- object_no, 0, std::move(data), mock_image_ctx.snapc, 0, {},
- &object_dispatch_flags, nullptr, &dispatch_result, &on_finish4,
+ object_no, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt,
+ {}, &object_dispatch_flags, nullptr, &dispatch_result, &on_finish4,
&on_dispatched4));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
ASSERT_NE(on_finish4, &cond4);
C_SaferCond cond1;
Context *on_finish1 = &cond1;
ASSERT_FALSE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, nullptr, &on_finish1, nullptr));
ASSERT_NE(on_finish1, &cond1);
Context *on_finish2 = &cond2;
C_SaferCond on_dispatched;
ASSERT_TRUE(mock_simple_scheduler_object_dispatch.write(
- 0, 0, std::move(data), mock_image_ctx.snapc, 0, {},
+ 0, 0, std::move(data), mock_image_ctx.snapc, 0, 0, std::nullopt, {},
&object_dispatch_flags, nullptr, &dispatch_result, &on_finish2,
&on_dispatched));
ASSERT_EQ(dispatch_result, io::DISPATCH_RESULT_COMPLETE);
dispatch_result, on_dispatched);
}
- MOCK_METHOD8(execute_write,
+ MOCK_METHOD10(execute_write,
bool(uint64_t, uint64_t, const ceph::bufferlist&,
- const ::SnapContext &, int*, uint64_t*, DispatchResult*,
- Context *));
+ const ::SnapContext &, int, std::optional<uint64_t>, int*,
+ uint64_t*, DispatchResult*, Context *));
bool write(
uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data,
- const ::SnapContext &snapc, int op_flags,
+ const ::SnapContext &snapc, int op_flags, int write_flags,
+ std::optional<uint64_t> assert_version,
const ZTracer::Trace &parent_trace, int* dispatch_flags,
uint64_t* journal_tid, DispatchResult* dispatch_result,
Context** on_finish, Context* on_dispatched) override {
- return execute_write(object_no, object_off, data, snapc, dispatch_flags,
- journal_tid, dispatch_result, on_dispatched);
+ return execute_write(object_no, object_off, data, snapc, write_flags,
+ assert_version, dispatch_flags, journal_tid,
+ dispatch_result, on_dispatched);
}
MOCK_METHOD10(execute_write_same,