Skip to content

Commit 6de55cb

Browse files
authored
Merge pull request ceph#50530 from Matan-B/wip-matanb-crimson-only-new-rbd-v2
crimson/osd: Handle rollback to head obejct Reviewed-by: Samuel Just <[email protected]>
2 parents dbe797b + b4f453d commit 6de55cb

File tree

3 files changed

+118
-7
lines changed

3 files changed

+118
-7
lines changed

src/crimson/osd/pg_backend.cc

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -784,27 +784,43 @@ PGBackend::rollback_iertr::future<> PGBackend::rollback(
784784
__func__, os.oi.soid ,snapid);
785785
hobject_t target_coid = os.oi.soid;
786786
target_coid.snap = snapid;
787-
return obc_loader.with_clone_obc_only<RWState::RWREAD>(
787+
return obc_loader.with_clone_obc_only<RWState::RWWRITE>(
788788
head, target_coid,
789789
[this, &os, &txn, &delta_stats, &osd_op_params]
790-
(auto clone_obc) {
790+
(auto resolved_obc) {
791+
if (resolved_obc->obs.oi.soid.is_head()) {
792+
// no-op: The resolved oid returned the head object
793+
logger().debug("PGBackend::rollback: loaded head_obc: {}"
794+
" do nothing",
795+
resolved_obc->obs.oi.soid);
796+
return rollback_iertr::now();
797+
}
798+
/* TODO: https://tracker.ceph.com/issues/59114 This implementation will not
799+
* behave correctly for a rados operation consisting of a mutation followed
800+
* by a rollback to a snapshot since the last mutation of the object.
801+
* The correct behavior would be for the rollback to undo the mutation
802+
* earlier in the operation by resolving to the clone created at the start
803+
* of the operation (see resolve_oid).
804+
* Instead, it will select HEAD leaving that mutation intact since the SnapSet won't
805+
* yet contain that clone. This behavior exists in classic as well.
806+
*/
791807
logger().debug("PGBackend::rollback: loaded clone_obc: {}",
792-
clone_obc->obs.oi.soid);
808+
resolved_obc->obs.oi.soid);
793809
// 1) Delete current head
794810
if (os.exists) {
795811
txn.remove(coll->get_cid(), ghobject_t{os.oi.soid,
796812
ghobject_t::NO_GEN, shard});
797813
}
798814
// 2) Clone correct snapshot into head
799-
txn.clone(coll->get_cid(), ghobject_t{clone_obc->obs.oi.soid},
815+
txn.clone(coll->get_cid(), ghobject_t{resolved_obc->obs.oi.soid},
800816
ghobject_t{os.oi.soid});
801817
// Copy clone obc.os.oi to os.oi
802818
os.oi.clear_flag(object_info_t::FLAG_WHITEOUT);
803-
os.oi.copy_user_bits(clone_obc->obs.oi);
819+
os.oi.copy_user_bits(resolved_obc->obs.oi);
804820
delta_stats.num_bytes -= os.oi.size;
805-
delta_stats.num_bytes += clone_obc->obs.oi.size;
821+
delta_stats.num_bytes += resolved_obc->obs.oi.size;
806822
osd_op_params.clean_regions.mark_data_region_dirty(0,
807-
std::max(os.oi.size, clone_obc->obs.oi.size));
823+
std::max(os.oi.size, resolved_obc->obs.oi.size));
808824
osd_op_params.clean_regions.mark_omap_dirty();
809825
// TODO: 3) Calculate clone_overlaps by following overlaps
810826
// forward from rollback snapshot

src/test/librados/snapshots.cc

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ TEST_F(LibRadosSnapshotsSelfManaged, Rollback) {
131131
::std::reverse(my_snaps.begin(), my_snaps.end());
132132
char buf[bufsize];
133133
memset(buf, 0xcc, sizeof(buf));
134+
// First write
134135
ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
135136

136137
my_snaps.push_back(-2);
@@ -141,7 +142,9 @@ TEST_F(LibRadosSnapshotsSelfManaged, Rollback) {
141142
::std::reverse(my_snaps.begin(), my_snaps.end());
142143
char buf2[sizeof(buf)];
143144
memset(buf2, 0xdd, sizeof(buf2));
145+
// Second write
144146
ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0));
147+
// Rollback to my_snaps[1] - Object is expeceted to conatin the first write
145148
rados_ioctx_selfmanaged_snap_rollback(ioctx, "foo", my_snaps[1]);
146149
char buf3[sizeof(buf)];
147150
ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
@@ -154,6 +157,51 @@ TEST_F(LibRadosSnapshotsSelfManaged, Rollback) {
154157
ASSERT_EQ(0, rados_remove(ioctx, "foo"));
155158
}
156159

160+
TEST_F(LibRadosSnapshotsSelfManaged, FutureSnapRollback) {
161+
std::vector<uint64_t> my_snaps;
162+
// Snapshot 1
163+
my_snaps.push_back(-2);
164+
ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back()));
165+
::std::reverse(my_snaps.begin(), my_snaps.end());
166+
ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0],
167+
&my_snaps[0], my_snaps.size()));
168+
::std::reverse(my_snaps.begin(), my_snaps.end());
169+
char buf[bufsize];
170+
memset(buf, 0xcc, sizeof(buf));
171+
// First write
172+
ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
173+
174+
// Snapshot 2
175+
my_snaps.push_back(-2);
176+
ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back()));
177+
::std::reverse(my_snaps.begin(), my_snaps.end());
178+
ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_set_write_ctx(ioctx, my_snaps[0],
179+
&my_snaps[0], my_snaps.size()));
180+
::std::reverse(my_snaps.begin(), my_snaps.end());
181+
char buf2[sizeof(buf)];
182+
memset(buf2, 0xdd, sizeof(buf2));
183+
// Second write
184+
ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0));
185+
// Snapshot 3
186+
my_snaps.push_back(-2);
187+
ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_create(ioctx, &my_snaps.back()));
188+
189+
// Rollback to the last snap id - Object is expected to conatin
190+
// latest write (head object)
191+
rados_ioctx_selfmanaged_snap_rollback(ioctx, "foo", my_snaps[2]);
192+
char buf3[sizeof(buf)];
193+
ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
194+
ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf)));
195+
196+
ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back()));
197+
my_snaps.pop_back();
198+
ASSERT_EQ(0, rados_ioctx_selfmanaged_snap_remove(ioctx, my_snaps.back()));
199+
my_snaps.pop_back();
200+
ASSERT_EQ(0, rados_remove(ioctx, "foo"));
201+
}
202+
203+
204+
157205
// EC testing
158206
TEST_F(LibRadosSnapshotsEC, SnapList) {
159207
SKIP_IF_CRIMSON();

src/test/librados/snapshots_cxx.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,53 @@ TEST_F(LibRadosSnapshotsSelfManagedPP, OrderSnap) {
458458
comp4->release();
459459
}
460460

461+
TEST_F(LibRadosSnapshotsSelfManagedPP, WriteRollback) {
462+
// https://tracker.ceph.com/issues/59114
463+
GTEST_SKIP();
464+
uint64_t snapid = 5;
465+
466+
// buf1
467+
char buf[bufsize];
468+
memset(buf, 0xcc, sizeof(buf));
469+
bufferlist bl;
470+
bl.append(buf, sizeof(buf));
471+
472+
// buf2
473+
char buf2[sizeof(buf)];
474+
memset(buf2, 0xdd, sizeof(buf2));
475+
bufferlist bl2;
476+
bl2.append(buf2, sizeof(buf2));
477+
478+
// First write
479+
ObjectWriteOperation op_write1;
480+
op_write1.write(0, bl);
481+
// Operate
482+
librados::AioCompletion *comp_write = cluster.aio_create_completion();
483+
ASSERT_EQ(0, ioctx.aio_operate("foo", comp_write, &op_write1, 0));
484+
ASSERT_EQ(0, comp_write->wait_for_complete());
485+
ASSERT_EQ(0, comp_write->get_return_value());
486+
comp_write->release();
487+
488+
// Take Snapshot
489+
ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&snapid));
490+
491+
// Rollback + Second write in the same op
492+
ObjectWriteOperation op_write2_snap_rollback;
493+
op_write2_snap_rollback.write(0, bl2);
494+
op_write2_snap_rollback.selfmanaged_snap_rollback(snapid);
495+
// Operate
496+
librados::AioCompletion *comp_write2 = cluster.aio_create_completion();
497+
ASSERT_EQ(0, ioctx.aio_operate("foo", comp_write2, &op_write2_snap_rollback, 0));
498+
ASSERT_EQ(0, comp_write2->wait_for_complete());
499+
ASSERT_EQ(0, comp_write2->get_return_value());
500+
comp_write2->release();
501+
502+
// Resolved should be first write
503+
bufferlist bl3;
504+
EXPECT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
505+
EXPECT_EQ(0, memcmp(buf, bl3.c_str(), sizeof(buf)));
506+
}
507+
461508
TEST_F(LibRadosSnapshotsSelfManagedPP, ReusePurgedSnap) {
462509
std::vector<uint64_t> my_snaps;
463510
my_snaps.push_back(-2);

0 commit comments

Comments
 (0)