}
}
+TEST_F(TestImageSync, Resize) {
+ int64_t object_size = std::min<int64_t>(
+ m_remote_image_ctx->size, 1 << m_remote_image_ctx->order);
+
+ uint64_t off = 0;
+ uint64_t len = object_size / 10;
+
+ std::string str(len, '1');
+ ASSERT_EQ((int)len, m_remote_image_ctx->aio_work_queue->write(off, len,
+ str.c_str(), 0));
+ {
+ RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
+ ASSERT_EQ(0, m_remote_image_ctx->flush());
+ }
+
+ ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr));
+
+ uint64_t size = object_size - 1;
+ librbd::NoOpProgressContext no_op_progress_ctx;
+ ASSERT_EQ(0, m_remote_image_ctx->operations->resize(size, true,
+ no_op_progress_ctx));
+
+ C_SaferCond ctx;
+ ImageSync<> *request = create_request(&ctx);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+
+ bufferlist read_remote_bl;
+ read_remote_bl.append(std::string(len, '\0'));
+ bufferlist read_local_bl;
+ read_local_bl.append(std::string(len, '\0'));
+
+ ASSERT_LE(0, m_remote_image_ctx->aio_work_queue->read(
+ off, len, read_remote_bl.c_str(), 0));
+ ASSERT_LE(0, m_local_image_ctx->aio_work_queue->read(
+ off, len, read_local_bl.c_str(), 0));
+
+ ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
+}
+
+TEST_F(TestImageSync, Discard) {
+ int64_t object_size = std::min<int64_t>(
+ m_remote_image_ctx->size, 1 << m_remote_image_ctx->order);
+
+ uint64_t off = 0;
+ uint64_t len = object_size / 10;
+
+ std::string str(len, '1');
+ ASSERT_EQ((int)len, m_remote_image_ctx->aio_work_queue->write(off, len,
+ str.c_str(), 0));
+ {
+ RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
+ ASSERT_EQ(0, m_remote_image_ctx->flush());
+ }
+
+ ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap", nullptr));
+
+ ASSERT_EQ((int)len - 2, m_remote_image_ctx->aio_work_queue->discard(off + 1,
+ len - 2));
+ {
+ RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock);
+ ASSERT_EQ(0, m_remote_image_ctx->flush());
+ }
+
+ C_SaferCond ctx;
+ ImageSync<> *request = create_request(&ctx);
+ request->send();
+ ASSERT_EQ(0, ctx.wait());
+
+ bufferlist read_remote_bl;
+ read_remote_bl.append(std::string(object_size, '\0'));
+ bufferlist read_local_bl;
+ read_local_bl.append(std::string(object_size, '\0'));
+
+ ASSERT_LE(0, m_remote_image_ctx->aio_work_queue->read(
+ off, len, read_remote_bl.c_str(), 0));
+ ASSERT_LE(0, m_local_image_ctx->aio_work_queue->read(
+ off, len, read_local_bl.c_str(), 0));
+
+ ASSERT_TRUE(read_remote_bl.contents_equal(read_local_bl));
+}
+
TEST_F(TestImageSync, SnapshotStress) {
std::list<std::string> snap_names;
auto &sync_ops = m_snap_sync_ops.begin()->second;
assert(!sync_ops.empty());
+ uint64_t object_offset;
uint64_t buffer_offset;
librados::ObjectWriteOperation op;
for (auto &sync_op : sync_ops) {
switch (std::get<0>(sync_op)) {
case SYNC_OP_TYPE_WRITE:
+ object_offset = std::get<1>(sync_op);
buffer_offset = 0;
- for(auto it : std::get<4>(sync_op)){
- bufferlist tmpbl;
- tmpbl.substr_of(std::get<3>(sync_op), buffer_offset, it.second);
- op.write(it.first, tmpbl);
- op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL |
- LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
- buffer_offset += it.second;
- dout(20) << ": write op: " << it.first<< "~" << it.second << dendl;
+ for (auto it : std::get<4>(sync_op)) {
+ if (object_offset < it.first) {
+ dout(20) << ": zero op: " << object_offset << "~"
+ << it.first - object_offset << dendl;
+ op.zero(object_offset, it.first - object_offset);
+ }
+ dout(20) << ": write op: " << it.first << "~" << it.second << dendl;
+ bufferlist tmpbl;
+ tmpbl.substr_of(std::get<3>(sync_op), buffer_offset, it.second);
+ op.write(it.first, tmpbl);
+ op.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL |
+ LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
+ buffer_offset += it.second;
+ object_offset = it.first + it.second;
+ }
+ if (object_offset < std::get<1>(sync_op) + std::get<2>(sync_op)) {
+ uint64_t sync_op_end = std::get<1>(sync_op) + std::get<2>(sync_op);
+ assert(sync_op_end <= m_snap_object_sizes[remote_snap_seq]);
+ if (sync_op_end == m_snap_object_sizes[remote_snap_seq]) {
+ dout(20) << ": trunc op: " << object_offset << dendl;
+ op.truncate(object_offset);
+ m_snap_object_sizes[remote_snap_seq] = object_offset;
+ } else {
+ dout(20) << ": zero op: " << object_offset << "~"
+ << sync_op_end - object_offset << dendl;
+ op.zero(object_offset, sync_op_end - object_offset);
+ }
}
break;
case SYNC_OP_TYPE_TRUNC:
+ if (std::get<1>(sync_op) > m_snap_object_sizes[remote_snap_seq]) {
+ // skip (must have been updated in WRITE op case issuing trunc op)
+ break;
+ }
dout(20) << ": trunc op: " << std::get<1>(sync_op) << dendl;
op.truncate(std::get<1>(sync_op));
break;
bufferlist(),
std::map<uint64_t, uint64_t>());
}
+ m_snap_object_sizes[end_remote_snap_id] = end_size;
} else {
if (prev_exists) {
// object remove