1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "cls/rbd/cls_rbd_types.h"
7 #include "cls/journal/cls_journal_types.h"
8 #include "cls/journal/cls_journal_client.h"
9 #include "journal/Journaler.h"
10 #include "librbd/ExclusiveLock.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/ImageWatcher.h"
14 #include "librbd/internal.h"
15 #include "librbd/Journal.h"
16 #include "librbd/Operations.h"
17 #include "librbd/io/AioCompletion.h"
18 #include "librbd/io/ImageDispatchSpec.h"
19 #include "librbd/io/ImageRequest.h"
20 #include "librbd/io/ImageRequestWQ.h"
21 #include "librbd/io/ReadResult.h"
22 #include "librbd/journal/Types.h"
24 void register_test_journal_replay() {
27 class TestJournalReplay
: public TestFixture
{
30 int when_acquired_lock(librbd::ImageCtx
*ictx
) {
33 RWLock::WLocker
owner_locker(ictx
->owner_lock
);
34 ictx
->exclusive_lock
->acquire_lock(&lock_ctx
);
36 int r
= lock_ctx
.wait();
41 C_SaferCond refresh_ctx
;
42 ictx
->state
->refresh(&refresh_ctx
);
43 return refresh_ctx
.wait();
47 void inject_into_journal(librbd::ImageCtx
*ictx
, T event
) {
49 librbd::journal::EventEntry
event_entry(event
);
51 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
52 uint64_t tid
= ictx
->journal
->append_io_event(std::move(event_entry
),0, 0,
54 ictx
->journal
->wait_event(tid
, &ctx
);
56 ASSERT_EQ(0, ctx
.wait());
59 void get_journal_commit_position(librbd::ImageCtx
*ictx
, int64_t *tag
,
62 const std::string client_id
= "";
63 std::string journal_id
= ictx
->id
;
65 C_SaferCond close_cond
;
66 ictx
->journal
->close(&close_cond
);
67 ASSERT_EQ(0, close_cond
.wait());
69 ictx
->journal
= nullptr;
74 std::set
<cls::journal::Client
> registered_clients
;
75 std::string oid
= ::journal::Journaler::header_oid(journal_id
);
76 cls::journal::client::get_mutable_metadata(ictx
->md_ctx
, oid
, &minimum_set
,
77 &active_set
, ®istered_clients
, &cond
);
78 ASSERT_EQ(0, cond
.wait());
79 std::set
<cls::journal::Client
>::const_iterator c
;
80 for (c
= registered_clients
.begin(); c
!= registered_clients
.end(); ++c
) {
81 if (c
->id
== client_id
) {
85 if (c
== registered_clients
.end() ||
86 c
->commit_position
.object_positions
.empty()) {
90 const cls::journal::ObjectPosition
&object_position
=
91 *c
->commit_position
.object_positions
.begin();
92 *tag
= object_position
.tag_tid
;
93 *entry
= object_position
.entry_tid
;
96 C_SaferCond open_cond
;
97 ictx
->journal
= new librbd::Journal
<>(*ictx
);
98 ictx
->journal
->open(&open_cond
);
99 ASSERT_EQ(0, open_cond
.wait());
103 TEST_F(TestJournalReplay
, AioDiscardEvent
) {
104 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
106 // write to the image w/o using the journal
107 librbd::ImageCtx
*ictx
;
108 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
109 ictx
->features
&= ~RBD_FEATURE_JOURNALING
;
111 std::string
payload(4096, '1');
112 bufferlist payload_bl
;
113 payload_bl
.append(payload
);
114 auto aio_comp
= new librbd::io::AioCompletion();
115 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
116 std::move(payload_bl
), 0);
117 ASSERT_EQ(0, aio_comp
->wait_for_complete());
120 aio_comp
= new librbd::io::AioCompletion();
121 ictx
->io_work_queue
->aio_flush(aio_comp
);
122 ASSERT_EQ(0, aio_comp
->wait_for_complete());
125 std::string
read_payload(4096, '\0');
126 librbd::io::ReadResult read_result
{&read_payload
[0], read_payload
.size()};
127 aio_comp
= new librbd::io::AioCompletion();
128 ictx
->io_work_queue
->aio_read(aio_comp
, 0, read_payload
.size(),
129 librbd::io::ReadResult
{read_result
}, 0);
130 ASSERT_EQ(0, aio_comp
->wait_for_complete());
132 ASSERT_EQ(payload
, read_payload
);
135 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
136 ASSERT_EQ(0, when_acquired_lock(ictx
));
138 // get current commit position
140 int64_t initial_entry
;
141 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
143 // inject a discard operation into the journal
144 inject_into_journal(ictx
,
145 librbd::journal::AioDiscardEvent(
146 0, payload
.size(), ictx
->discard_granularity_bytes
));
149 // re-open the journal so that it replays the new entry
150 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
151 ASSERT_EQ(0, when_acquired_lock(ictx
));
153 aio_comp
= new librbd::io::AioCompletion();
154 ictx
->io_work_queue
->aio_read(aio_comp
, 0, read_payload
.size(),
155 librbd::io::ReadResult
{read_result
}, 0);
156 ASSERT_EQ(0, aio_comp
->wait_for_complete());
158 if (ictx
->discard_granularity_bytes
> 0) {
159 ASSERT_EQ(payload
, read_payload
);
161 ASSERT_EQ(std::string(read_payload
.size(), '\0'), read_payload
);
164 // check the commit position is properly updated
166 int64_t current_entry
;
167 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
168 ASSERT_EQ(initial_tag
+ 1, current_tag
);
169 ASSERT_EQ(0, current_entry
);
171 // replay several envents and check the commit position
172 inject_into_journal(ictx
,
173 librbd::journal::AioDiscardEvent(
174 0, payload
.size(), ictx
->discard_granularity_bytes
));
175 inject_into_journal(ictx
,
176 librbd::journal::AioDiscardEvent(
177 0, payload
.size(), ictx
->discard_granularity_bytes
));
180 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
181 ASSERT_EQ(0, when_acquired_lock(ictx
));
182 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
183 ASSERT_EQ(initial_tag
+ 2, current_tag
);
184 ASSERT_EQ(1, current_entry
);
186 // verify lock ordering constraints
187 aio_comp
= new librbd::io::AioCompletion();
188 ictx
->io_work_queue
->aio_discard(aio_comp
, 0, read_payload
.size(),
189 ictx
->discard_granularity_bytes
);
190 ASSERT_EQ(0, aio_comp
->wait_for_complete());
194 TEST_F(TestJournalReplay
, AioWriteEvent
) {
195 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
197 librbd::ImageCtx
*ictx
;
198 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
199 ASSERT_EQ(0, when_acquired_lock(ictx
));
201 // get current commit position
203 int64_t initial_entry
;
204 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
206 // inject a write operation into the journal
207 std::string
payload(4096, '1');
208 bufferlist payload_bl
;
209 payload_bl
.append(payload
);
210 inject_into_journal(ictx
,
211 librbd::journal::AioWriteEvent(0, payload
.size(), payload_bl
));
214 // re-open the journal so that it replays the new entry
215 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
216 ASSERT_EQ(0, when_acquired_lock(ictx
));
218 std::string
read_payload(4096, '\0');
219 librbd::io::ReadResult read_result
{&read_payload
[0], read_payload
.size()};
220 auto aio_comp
= new librbd::io::AioCompletion();
221 ictx
->io_work_queue
->aio_read(aio_comp
, 0, read_payload
.size(),
222 std::move(read_result
), 0);
223 ASSERT_EQ(0, aio_comp
->wait_for_complete());
225 ASSERT_EQ(payload
, read_payload
);
227 // check the commit position is properly updated
229 int64_t current_entry
;
230 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
231 ASSERT_EQ(initial_tag
+ 1, current_tag
);
232 ASSERT_EQ(0, current_entry
);
234 // replay several events and check the commit position
235 inject_into_journal(ictx
,
236 librbd::journal::AioWriteEvent(0, payload
.size(), payload_bl
));
237 inject_into_journal(ictx
,
238 librbd::journal::AioWriteEvent(0, payload
.size(), payload_bl
));
241 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
242 ASSERT_EQ(0, when_acquired_lock(ictx
));
243 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
244 ASSERT_EQ(initial_tag
+ 2, current_tag
);
245 ASSERT_EQ(1, current_entry
);
247 // verify lock ordering constraints
248 aio_comp
= new librbd::io::AioCompletion();
249 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
250 bufferlist
{payload_bl
}, 0);
251 ASSERT_EQ(0, aio_comp
->wait_for_complete());
255 TEST_F(TestJournalReplay
, AioFlushEvent
) {
256 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
258 librbd::ImageCtx
*ictx
;
260 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
261 ASSERT_EQ(0, when_acquired_lock(ictx
));
263 // get current commit position
265 int64_t initial_entry
;
266 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
268 // inject a flush operation into the journal
269 inject_into_journal(ictx
, librbd::journal::AioFlushEvent());
272 // re-open the journal so that it replays the new entry
273 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
274 ASSERT_EQ(0, when_acquired_lock(ictx
));
276 // check the commit position is properly updated
278 int64_t current_entry
;
279 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
280 ASSERT_EQ(initial_tag
+ 1, current_tag
);
281 ASSERT_EQ(0, current_entry
);
283 // replay several events and check the commit position
284 inject_into_journal(ictx
, librbd::journal::AioFlushEvent());
285 inject_into_journal(ictx
, librbd::journal::AioFlushEvent());
288 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
289 ASSERT_EQ(0, when_acquired_lock(ictx
));
290 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
291 ASSERT_EQ(initial_tag
+ 2, current_tag
);
292 ASSERT_EQ(1, current_entry
);
294 // verify lock ordering constraints
295 auto aio_comp
= new librbd::io::AioCompletion();
296 ictx
->io_work_queue
->aio_flush(aio_comp
);
297 ASSERT_EQ(0, aio_comp
->wait_for_complete());
301 TEST_F(TestJournalReplay
, SnapCreate
) {
302 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
304 librbd::ImageCtx
*ictx
;
306 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
307 ASSERT_EQ(0, when_acquired_lock(ictx
));
309 // get current commit position
311 int64_t initial_entry
;
312 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
314 // inject snapshot ops into journal
315 inject_into_journal(ictx
, librbd::journal::SnapCreateEvent(1, cls::rbd::UserSnapshotNamespace(),
317 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
321 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
322 ASSERT_EQ(0, when_acquired_lock(ictx
));
325 int64_t current_entry
;
326 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
327 ASSERT_EQ(initial_tag
+ 1, current_tag
);
328 ASSERT_EQ(1, current_entry
);
331 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
332 ASSERT_NE(CEPH_NOSNAP
, ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(),
336 // verify lock ordering constraints
337 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
341 TEST_F(TestJournalReplay
, SnapProtect
) {
342 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
344 librbd::ImageCtx
*ictx
;
346 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
347 ASSERT_EQ(0, when_acquired_lock(ictx
));
349 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
352 // get current commit position
354 int64_t initial_entry
;
355 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
357 // inject snapshot ops into journal
358 inject_into_journal(ictx
,
359 librbd::journal::SnapProtectEvent(1,
360 cls::rbd::UserSnapshotNamespace(),
362 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
366 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
367 ASSERT_EQ(0, when_acquired_lock(ictx
));
370 int64_t current_entry
;
371 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
372 ASSERT_EQ(initial_tag
, current_tag
);
373 ASSERT_EQ(initial_entry
+ 2, current_entry
);
376 ASSERT_EQ(0, librbd::snap_is_protected(ictx
, "snap", &is_protected
));
377 ASSERT_TRUE(is_protected
);
379 // verify lock ordering constraints
380 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
382 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
386 TEST_F(TestJournalReplay
, SnapUnprotect
) {
387 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
389 librbd::ImageCtx
*ictx
;
391 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
392 ASSERT_EQ(0, when_acquired_lock(ictx
));
394 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
398 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
399 snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
400 ASSERT_NE(CEPH_NOSNAP
, snap_id
);
402 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
405 // get current commit position
407 int64_t initial_entry
;
408 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
410 // inject snapshot ops into journal
411 inject_into_journal(ictx
,
412 librbd::journal::SnapUnprotectEvent(1,
413 cls::rbd::UserSnapshotNamespace(),
415 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
419 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
420 ASSERT_EQ(0, when_acquired_lock(ictx
));
423 int64_t current_entry
;
424 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
425 ASSERT_EQ(initial_tag
, current_tag
);
426 ASSERT_EQ(initial_entry
+ 2, current_entry
);
429 ASSERT_EQ(0, librbd::snap_is_protected(ictx
, "snap", &is_protected
));
430 ASSERT_FALSE(is_protected
);
432 // verify lock ordering constraints
433 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
435 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
437 ASSERT_EQ(0, ictx
->operations
->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
441 TEST_F(TestJournalReplay
, SnapRename
) {
442 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
444 librbd::ImageCtx
*ictx
;
446 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
447 ASSERT_EQ(0, when_acquired_lock(ictx
));
449 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
453 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
454 snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
455 ASSERT_NE(CEPH_NOSNAP
, snap_id
);
458 // get current commit position
460 int64_t initial_entry
;
461 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
463 // inject snapshot ops into journal
464 inject_into_journal(ictx
, librbd::journal::SnapRenameEvent(1, snap_id
, "snap",
466 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
470 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
471 ASSERT_EQ(0, when_acquired_lock(ictx
));
474 int64_t current_entry
;
475 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
476 ASSERT_EQ(initial_tag
, current_tag
);
477 ASSERT_EQ(initial_entry
+ 2, current_entry
);
478 ASSERT_EQ(0, ictx
->state
->refresh());
481 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
482 snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap2");
483 ASSERT_NE(CEPH_NOSNAP
, snap_id
);
486 // verify lock ordering constraints
487 ASSERT_EQ(0, ictx
->operations
->snap_rename("snap2", "snap3"));
490 TEST_F(TestJournalReplay
, SnapRollback
) {
491 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
493 librbd::ImageCtx
*ictx
;
495 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
496 ASSERT_EQ(0, when_acquired_lock(ictx
));
498 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
501 // get current commit position
503 int64_t initial_entry
;
504 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
506 // inject snapshot ops into journal
507 inject_into_journal(ictx
,
508 librbd::journal::SnapRollbackEvent(1,
509 cls::rbd::UserSnapshotNamespace(),
511 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
515 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
516 ASSERT_EQ(0, when_acquired_lock(ictx
));
519 int64_t current_entry
;
520 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
521 ASSERT_EQ(initial_tag
, current_tag
);
522 ASSERT_EQ(initial_entry
+ 2, current_entry
);
524 // verify lock ordering constraints
525 librbd::NoOpProgressContext no_op_progress
;
526 ASSERT_EQ(0, ictx
->operations
->snap_rollback(cls::rbd::UserSnapshotNamespace(),
531 TEST_F(TestJournalReplay
, SnapRemove
) {
532 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
534 librbd::ImageCtx
*ictx
;
536 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
537 ASSERT_EQ(0, when_acquired_lock(ictx
));
539 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
542 // get current commit position
544 int64_t initial_entry
;
545 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
547 // inject snapshot ops into journal
548 inject_into_journal(ictx
,
549 librbd::journal::SnapRemoveEvent(1,
550 cls::rbd::UserSnapshotNamespace(),
552 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
556 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
557 ASSERT_EQ(0, when_acquired_lock(ictx
));
560 int64_t current_entry
;
561 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
562 ASSERT_EQ(initial_tag
, current_tag
);
563 ASSERT_EQ(initial_entry
+ 2, current_entry
);
566 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
567 uint64_t snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(),
569 ASSERT_EQ(CEPH_NOSNAP
, snap_id
);
572 // verify lock ordering constraints
573 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
575 ASSERT_EQ(0, ictx
->operations
->snap_remove(cls::rbd::UserSnapshotNamespace(),
579 TEST_F(TestJournalReplay
, Rename
) {
580 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
582 librbd::ImageCtx
*ictx
;
584 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
585 ASSERT_EQ(0, when_acquired_lock(ictx
));
587 // get current commit position
589 int64_t initial_entry
;
590 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
592 // inject snapshot ops into journal
593 std::string
new_image_name(get_temp_image_name());
594 inject_into_journal(ictx
, librbd::journal::RenameEvent(1, new_image_name
));
595 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
599 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
600 ASSERT_EQ(0, when_acquired_lock(ictx
));
603 int64_t current_entry
;
604 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
605 ASSERT_EQ(initial_tag
+ 1, current_tag
);
606 ASSERT_EQ(1, current_entry
);
608 // verify lock ordering constraints
610 ASSERT_EQ(0, rbd
.rename(m_ioctx
, new_image_name
.c_str(), m_image_name
.c_str()));
613 TEST_F(TestJournalReplay
, Resize
) {
614 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
616 librbd::ImageCtx
*ictx
;
618 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
619 ASSERT_EQ(0, when_acquired_lock(ictx
));
621 // get current commit position
623 int64_t initial_entry
;
624 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
626 // inject snapshot ops into journal
627 inject_into_journal(ictx
, librbd::journal::ResizeEvent(1, 16));
628 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
632 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
633 ASSERT_EQ(0, when_acquired_lock(ictx
));
636 int64_t current_entry
;
637 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
638 ASSERT_EQ(initial_tag
+ 1, current_tag
);
639 ASSERT_EQ(1, current_entry
);
641 // verify lock ordering constraints
642 librbd::NoOpProgressContext no_op_progress
;
643 ASSERT_EQ(0, ictx
->operations
->resize(0, true, no_op_progress
));
646 TEST_F(TestJournalReplay
, Flatten
) {
647 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_JOURNALING
);
649 librbd::ImageCtx
*ictx
;
650 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
651 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
653 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
656 std::string clone_name
= get_temp_image_name();
657 int order
= ictx
->order
;
658 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap", m_ioctx
,
659 clone_name
.c_str(), ictx
->features
, &order
, 0, 0));
661 librbd::ImageCtx
*ictx2
;
662 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
663 ASSERT_EQ(0, when_acquired_lock(ictx2
));
665 // get current commit position
667 int64_t initial_entry
;
668 get_journal_commit_position(ictx2
, &initial_tag
, &initial_entry
);
670 // inject snapshot ops into journal
671 inject_into_journal(ictx2
, librbd::journal::FlattenEvent(1));
672 inject_into_journal(ictx2
, librbd::journal::OpFinishEvent(1, 0));
676 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
677 ASSERT_EQ(0, when_acquired_lock(ictx2
));
680 int64_t current_entry
;
681 get_journal_commit_position(ictx2
, ¤t_tag
, ¤t_entry
);
682 ASSERT_EQ(initial_tag
+ 1, current_tag
);
683 ASSERT_EQ(1, current_entry
);
684 ASSERT_EQ(0, ictx
->operations
->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
687 // verify lock ordering constraints
688 librbd::NoOpProgressContext no_op
;
689 ASSERT_EQ(-EINVAL
, ictx2
->operations
->flatten(no_op
));
692 TEST_F(TestJournalReplay
, UpdateFeatures
) {
693 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
695 librbd::ImageCtx
*ictx
;
697 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
698 ASSERT_EQ(0, when_acquired_lock(ictx
));
700 uint64_t features
= RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
;
701 bool enabled
= !ictx
->test_features(features
);
703 // get current commit position
705 int64_t initial_entry
;
706 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
708 // inject update_features op into journal
709 inject_into_journal(ictx
, librbd::journal::UpdateFeaturesEvent(1, features
,
714 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
715 ASSERT_EQ(0, when_acquired_lock(ictx
));
718 int64_t current_entry
;
719 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
720 ASSERT_EQ(initial_tag
+ 1, current_tag
);
721 ASSERT_EQ(0, current_entry
);
723 ASSERT_EQ(enabled
, ictx
->test_features(features
));
725 // verify lock ordering constraints
726 ASSERT_EQ(0, ictx
->operations
->update_features(features
, !enabled
));
729 TEST_F(TestJournalReplay
, MetadataSet
) {
730 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
732 librbd::ImageCtx
*ictx
;
734 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
735 ASSERT_EQ(0, when_acquired_lock(ictx
));
737 // get current commit position
739 int64_t initial_entry
;
740 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
742 // inject metadata_set op into journal
743 inject_into_journal(ictx
, librbd::journal::MetadataSetEvent(
744 1, "conf_rbd_mirroring_replay_delay", "9876"));
745 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
749 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
750 ASSERT_EQ(0, when_acquired_lock(ictx
));
753 int64_t current_entry
;
754 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
755 ASSERT_EQ(initial_tag
+ 1, current_tag
);
756 ASSERT_EQ(1, current_entry
);
758 ASSERT_EQ(9876U, ictx
->mirroring_replay_delay
);
761 ASSERT_EQ(0, librbd::metadata_get(ictx
, "conf_rbd_mirroring_replay_delay",
763 ASSERT_EQ("9876", value
);
765 // verify lock ordering constraints
766 ASSERT_EQ(0, ictx
->operations
->metadata_set("key2", "value"));
769 TEST_F(TestJournalReplay
, MetadataRemove
) {
770 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
772 librbd::ImageCtx
*ictx
;
774 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
775 ASSERT_EQ(0, when_acquired_lock(ictx
));
777 ASSERT_EQ(0, ictx
->operations
->metadata_set(
778 "conf_rbd_mirroring_replay_delay", "9876"));
780 // get current commit position
782 int64_t initial_entry
;
783 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
785 // inject metadata_remove op into journal
786 inject_into_journal(ictx
, librbd::journal::MetadataRemoveEvent(
787 1, "conf_rbd_mirroring_replay_delay"));
788 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
792 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
793 ASSERT_EQ(0, when_acquired_lock(ictx
));
796 int64_t current_entry
;
797 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
798 ASSERT_EQ(initial_tag
, current_tag
);
799 ASSERT_EQ(initial_entry
+ 2, current_entry
);
800 ASSERT_EQ(0U, ictx
->mirroring_replay_delay
);
804 librbd::metadata_get(ictx
, "conf_rbd_mirroring_replay_delay",
807 // verify lock ordering constraints
808 ASSERT_EQ(0, ictx
->operations
->metadata_set("key", "value"));
809 ASSERT_EQ(0, ictx
->operations
->metadata_remove("key"));
812 TEST_F(TestJournalReplay
, ObjectPosition
) {
813 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
815 librbd::ImageCtx
*ictx
;
816 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
817 ASSERT_EQ(0, when_acquired_lock(ictx
));
819 // get current commit position
821 int64_t initial_entry
;
822 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
824 std::string
payload(4096, '1');
825 bufferlist payload_bl
;
826 payload_bl
.append(payload
);
827 auto aio_comp
= new librbd::io::AioCompletion();
828 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
829 bufferlist
{payload_bl
}, 0);
830 ASSERT_EQ(0, aio_comp
->wait_for_complete());
833 aio_comp
= new librbd::io::AioCompletion();
834 ictx
->io_work_queue
->aio_flush(aio_comp
);
835 ASSERT_EQ(0, aio_comp
->wait_for_complete());
838 // check the commit position updated
840 int64_t current_entry
;
841 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
842 ASSERT_EQ(initial_tag
+ 1, current_tag
);
843 ASSERT_EQ(1, current_entry
);
847 aio_comp
= new librbd::io::AioCompletion();
848 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
849 bufferlist
{payload_bl
}, 0);
850 ASSERT_EQ(0, aio_comp
->wait_for_complete());
853 aio_comp
= new librbd::io::AioCompletion();
854 ictx
->io_work_queue
->aio_flush(aio_comp
);
855 ASSERT_EQ(0, aio_comp
->wait_for_complete());
858 // user flush requests are ignored when journaling + cache are enabled
859 C_SaferCond flush_ctx
;
860 aio_comp
= librbd::io::AioCompletion::create(
861 &flush_ctx
, ictx
, librbd::io::AIO_TYPE_FLUSH
);
862 auto req
= librbd::io::ImageDispatchSpec
<>::create_flush_request(
863 *ictx
, aio_comp
, librbd::io::FLUSH_SOURCE_INTERNAL
, {});
866 ASSERT_EQ(0, flush_ctx
.wait());
868 // check the commit position updated
869 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
870 ASSERT_EQ(initial_tag
+ 1, current_tag
);
871 ASSERT_EQ(3, current_entry
);