1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "cls/rbd/cls_rbd_types.h"
5 #include "test/librbd/test_fixture.h"
6 #include "test/librbd/test_support.h"
7 #include "cls/rbd/cls_rbd_types.h"
8 #include "cls/journal/cls_journal_types.h"
9 #include "cls/journal/cls_journal_client.h"
10 #include "journal/Journaler.h"
11 #include "librbd/ExclusiveLock.h"
12 #include "librbd/ImageCtx.h"
13 #include "librbd/ImageState.h"
14 #include "librbd/ImageWatcher.h"
15 #include "librbd/internal.h"
16 #include "librbd/Journal.h"
17 #include "librbd/Operations.h"
18 #include "librbd/io/AioCompletion.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
);
50 librbd::Journal
<>::IOObjectRequests requests
;
52 RWLock::RLocker
owner_locker(ictx
->owner_lock
);
53 uint64_t tid
= ictx
->journal
->append_io_event(std::move(event_entry
),
54 requests
, 0, 0, true);
55 ictx
->journal
->wait_event(tid
, &ctx
);
57 ASSERT_EQ(0, ctx
.wait());
60 void get_journal_commit_position(librbd::ImageCtx
*ictx
, int64_t *tag
,
63 const std::string client_id
= "";
64 std::string journal_id
= ictx
->id
;
66 C_SaferCond close_cond
;
67 ictx
->journal
->close(&close_cond
);
68 ASSERT_EQ(0, close_cond
.wait());
70 ictx
->journal
= nullptr;
75 std::set
<cls::journal::Client
> registered_clients
;
76 std::string oid
= ::journal::Journaler::header_oid(journal_id
);
77 cls::journal::client::get_mutable_metadata(ictx
->md_ctx
, oid
, &minimum_set
,
78 &active_set
, ®istered_clients
, &cond
);
79 ASSERT_EQ(0, cond
.wait());
80 std::set
<cls::journal::Client
>::const_iterator c
;
81 for (c
= registered_clients
.begin(); c
!= registered_clients
.end(); ++c
) {
82 if (c
->id
== client_id
) {
86 if (c
== registered_clients
.end() ||
87 c
->commit_position
.object_positions
.empty()) {
91 const cls::journal::ObjectPosition
&object_position
=
92 *c
->commit_position
.object_positions
.begin();
93 *tag
= object_position
.tag_tid
;
94 *entry
= object_position
.entry_tid
;
97 C_SaferCond open_cond
;
98 ictx
->journal
= new librbd::Journal
<>(*ictx
);
99 ictx
->journal
->open(&open_cond
);
100 ASSERT_EQ(0, open_cond
.wait());
104 TEST_F(TestJournalReplay
, AioDiscardEvent
) {
105 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
107 // write to the image w/o using the journal
108 librbd::ImageCtx
*ictx
;
109 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
110 ictx
->features
&= ~RBD_FEATURE_JOURNALING
;
112 std::string
payload(4096, '1');
113 bufferlist payload_bl
;
114 payload_bl
.append(payload
);
115 auto aio_comp
= new librbd::io::AioCompletion();
116 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
117 std::move(payload_bl
), 0);
118 ASSERT_EQ(0, aio_comp
->wait_for_complete());
121 aio_comp
= new librbd::io::AioCompletion();
122 ictx
->io_work_queue
->aio_flush(aio_comp
);
123 ASSERT_EQ(0, aio_comp
->wait_for_complete());
126 std::string
read_payload(4096, '\0');
127 librbd::io::ReadResult read_result
{&read_payload
[0], read_payload
.size()};
128 aio_comp
= new librbd::io::AioCompletion();
129 ictx
->io_work_queue
->aio_read(aio_comp
, 0, read_payload
.size(),
130 librbd::io::ReadResult
{read_result
}, 0);
131 ASSERT_EQ(0, aio_comp
->wait_for_complete());
133 ASSERT_EQ(payload
, read_payload
);
136 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
137 ASSERT_EQ(0, when_acquired_lock(ictx
));
139 // get current commit position
141 int64_t initial_entry
;
142 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
144 // inject a discard operation into the journal
145 inject_into_journal(ictx
,
146 librbd::journal::AioDiscardEvent(0, payload
.size(), ictx
->skip_partial_discard
));
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
->cct
->_conf
->rbd_skip_partial_discard
) {
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(0, payload
.size(), ictx
->cct
->_conf
->rbd_skip_partial_discard
));
174 inject_into_journal(ictx
,
175 librbd::journal::AioDiscardEvent(0, payload
.size(), ictx
->cct
->_conf
->rbd_skip_partial_discard
));
178 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
179 ASSERT_EQ(0, when_acquired_lock(ictx
));
180 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
181 ASSERT_EQ(initial_tag
+ 2, current_tag
);
182 ASSERT_EQ(1, current_entry
);
184 // verify lock ordering constraints
185 aio_comp
= new librbd::io::AioCompletion();
186 ictx
->io_work_queue
->aio_discard(aio_comp
, 0, read_payload
.size(), ictx
->cct
->_conf
->rbd_skip_partial_discard
);
187 ASSERT_EQ(0, aio_comp
->wait_for_complete());
191 TEST_F(TestJournalReplay
, AioWriteEvent
) {
192 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
194 librbd::ImageCtx
*ictx
;
195 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
196 ASSERT_EQ(0, when_acquired_lock(ictx
));
198 // get current commit position
200 int64_t initial_entry
;
201 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
203 // inject a write operation into the journal
204 std::string
payload(4096, '1');
205 bufferlist payload_bl
;
206 payload_bl
.append(payload
);
207 inject_into_journal(ictx
,
208 librbd::journal::AioWriteEvent(0, payload
.size(), payload_bl
));
211 // re-open the journal so that it replays the new entry
212 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
213 ASSERT_EQ(0, when_acquired_lock(ictx
));
215 std::string
read_payload(4096, '\0');
216 librbd::io::ReadResult read_result
{&read_payload
[0], read_payload
.size()};
217 auto aio_comp
= new librbd::io::AioCompletion();
218 ictx
->io_work_queue
->aio_read(aio_comp
, 0, read_payload
.size(),
219 std::move(read_result
), 0);
220 ASSERT_EQ(0, aio_comp
->wait_for_complete());
222 ASSERT_EQ(payload
, read_payload
);
224 // check the commit position is properly updated
226 int64_t current_entry
;
227 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
228 ASSERT_EQ(initial_tag
+ 1, current_tag
);
229 ASSERT_EQ(0, current_entry
);
231 // replay several events and check the commit position
232 inject_into_journal(ictx
,
233 librbd::journal::AioWriteEvent(0, payload
.size(), payload_bl
));
234 inject_into_journal(ictx
,
235 librbd::journal::AioWriteEvent(0, payload
.size(), payload_bl
));
238 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
239 ASSERT_EQ(0, when_acquired_lock(ictx
));
240 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
241 ASSERT_EQ(initial_tag
+ 2, current_tag
);
242 ASSERT_EQ(1, current_entry
);
244 // verify lock ordering constraints
245 aio_comp
= new librbd::io::AioCompletion();
246 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
247 bufferlist
{payload_bl
}, 0);
248 ASSERT_EQ(0, aio_comp
->wait_for_complete());
252 TEST_F(TestJournalReplay
, AioFlushEvent
) {
253 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
255 librbd::ImageCtx
*ictx
;
257 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
258 ASSERT_EQ(0, when_acquired_lock(ictx
));
260 // get current commit position
262 int64_t initial_entry
;
263 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
265 // inject a flush operation into the journal
266 inject_into_journal(ictx
, librbd::journal::AioFlushEvent());
269 // re-open the journal so that it replays the new entry
270 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
271 ASSERT_EQ(0, when_acquired_lock(ictx
));
273 // check the commit position is properly updated
275 int64_t current_entry
;
276 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
277 ASSERT_EQ(initial_tag
+ 1, current_tag
);
278 ASSERT_EQ(0, current_entry
);
280 // replay several events and check the commit position
281 inject_into_journal(ictx
, librbd::journal::AioFlushEvent());
282 inject_into_journal(ictx
, librbd::journal::AioFlushEvent());
285 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
286 ASSERT_EQ(0, when_acquired_lock(ictx
));
287 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
288 ASSERT_EQ(initial_tag
+ 2, current_tag
);
289 ASSERT_EQ(1, current_entry
);
291 // verify lock ordering constraints
292 auto aio_comp
= new librbd::io::AioCompletion();
293 ictx
->io_work_queue
->aio_flush(aio_comp
);
294 ASSERT_EQ(0, aio_comp
->wait_for_complete());
298 TEST_F(TestJournalReplay
, SnapCreate
) {
299 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
301 librbd::ImageCtx
*ictx
;
303 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
304 ASSERT_EQ(0, when_acquired_lock(ictx
));
306 // get current commit position
308 int64_t initial_entry
;
309 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
311 // inject snapshot ops into journal
312 inject_into_journal(ictx
, librbd::journal::SnapCreateEvent(1, cls::rbd::UserSnapshotNamespace(),
314 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
318 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
319 ASSERT_EQ(0, when_acquired_lock(ictx
));
322 int64_t current_entry
;
323 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
324 ASSERT_EQ(initial_tag
+ 1, current_tag
);
325 ASSERT_EQ(1, current_entry
);
328 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
329 ASSERT_NE(CEPH_NOSNAP
, ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(),
333 // verify lock ordering constraints
334 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
338 TEST_F(TestJournalReplay
, SnapProtect
) {
339 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
341 librbd::ImageCtx
*ictx
;
343 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
344 ASSERT_EQ(0, when_acquired_lock(ictx
));
346 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
349 // get current commit position
351 int64_t initial_entry
;
352 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
354 // inject snapshot ops into journal
355 inject_into_journal(ictx
,
356 librbd::journal::SnapProtectEvent(1,
357 cls::rbd::UserSnapshotNamespace(),
359 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
363 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
364 ASSERT_EQ(0, when_acquired_lock(ictx
));
367 int64_t current_entry
;
368 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
369 ASSERT_EQ(initial_tag
, current_tag
);
370 ASSERT_EQ(initial_entry
+ 2, current_entry
);
373 ASSERT_EQ(0, librbd::snap_is_protected(ictx
, "snap", &is_protected
));
374 ASSERT_TRUE(is_protected
);
376 // verify lock ordering constraints
377 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
379 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
383 TEST_F(TestJournalReplay
, SnapUnprotect
) {
384 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
386 librbd::ImageCtx
*ictx
;
388 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
389 ASSERT_EQ(0, when_acquired_lock(ictx
));
391 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
395 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
396 snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
397 ASSERT_NE(CEPH_NOSNAP
, snap_id
);
399 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
402 // get current commit position
404 int64_t initial_entry
;
405 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
407 // inject snapshot ops into journal
408 inject_into_journal(ictx
,
409 librbd::journal::SnapUnprotectEvent(1,
410 cls::rbd::UserSnapshotNamespace(),
412 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
416 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
417 ASSERT_EQ(0, when_acquired_lock(ictx
));
420 int64_t current_entry
;
421 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
422 ASSERT_EQ(initial_tag
, current_tag
);
423 ASSERT_EQ(initial_entry
+ 2, current_entry
);
426 ASSERT_EQ(0, librbd::snap_is_protected(ictx
, "snap", &is_protected
));
427 ASSERT_FALSE(is_protected
);
429 // verify lock ordering constraints
430 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
432 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
434 ASSERT_EQ(0, ictx
->operations
->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
438 TEST_F(TestJournalReplay
, SnapRename
) {
439 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
441 librbd::ImageCtx
*ictx
;
443 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
444 ASSERT_EQ(0, when_acquired_lock(ictx
));
446 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
450 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
451 snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
452 ASSERT_NE(CEPH_NOSNAP
, snap_id
);
455 // get current commit position
457 int64_t initial_entry
;
458 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
460 // inject snapshot ops into journal
461 inject_into_journal(ictx
, librbd::journal::SnapRenameEvent(1, snap_id
, "snap",
463 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
467 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
468 ASSERT_EQ(0, when_acquired_lock(ictx
));
471 int64_t current_entry
;
472 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
473 ASSERT_EQ(initial_tag
, current_tag
);
474 ASSERT_EQ(initial_entry
+ 2, current_entry
);
475 ASSERT_EQ(0, ictx
->state
->refresh());
478 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
479 snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap2");
480 ASSERT_NE(CEPH_NOSNAP
, snap_id
);
483 // verify lock ordering constraints
484 ASSERT_EQ(0, ictx
->operations
->snap_rename("snap2", "snap3"));
487 TEST_F(TestJournalReplay
, SnapRollback
) {
488 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
490 librbd::ImageCtx
*ictx
;
492 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
493 ASSERT_EQ(0, when_acquired_lock(ictx
));
495 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
498 // get current commit position
500 int64_t initial_entry
;
501 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
503 // inject snapshot ops into journal
504 inject_into_journal(ictx
,
505 librbd::journal::SnapRollbackEvent(1,
506 cls::rbd::UserSnapshotNamespace(),
508 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
512 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
513 ASSERT_EQ(0, when_acquired_lock(ictx
));
516 int64_t current_entry
;
517 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
518 ASSERT_EQ(initial_tag
, current_tag
);
519 ASSERT_EQ(initial_entry
+ 2, current_entry
);
521 // verify lock ordering constraints
522 librbd::NoOpProgressContext no_op_progress
;
523 ASSERT_EQ(0, ictx
->operations
->snap_rollback(cls::rbd::UserSnapshotNamespace(),
528 TEST_F(TestJournalReplay
, SnapRemove
) {
529 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
531 librbd::ImageCtx
*ictx
;
533 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
534 ASSERT_EQ(0, when_acquired_lock(ictx
));
536 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
539 // get current commit position
541 int64_t initial_entry
;
542 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
544 // inject snapshot ops into journal
545 inject_into_journal(ictx
,
546 librbd::journal::SnapRemoveEvent(1,
547 cls::rbd::UserSnapshotNamespace(),
549 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
553 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
554 ASSERT_EQ(0, when_acquired_lock(ictx
));
557 int64_t current_entry
;
558 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
559 ASSERT_EQ(initial_tag
, current_tag
);
560 ASSERT_EQ(initial_entry
+ 2, current_entry
);
563 RWLock::RLocker
snap_locker(ictx
->snap_lock
);
564 uint64_t snap_id
= ictx
->get_snap_id(cls::rbd::UserSnapshotNamespace(),
566 ASSERT_EQ(CEPH_NOSNAP
, snap_id
);
569 // verify lock ordering constraints
570 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
572 ASSERT_EQ(0, ictx
->operations
->snap_remove(cls::rbd::UserSnapshotNamespace(),
576 TEST_F(TestJournalReplay
, Rename
) {
577 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
579 librbd::ImageCtx
*ictx
;
581 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
582 ASSERT_EQ(0, when_acquired_lock(ictx
));
584 // get current commit position
586 int64_t initial_entry
;
587 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
589 // inject snapshot ops into journal
590 std::string
new_image_name(get_temp_image_name());
591 inject_into_journal(ictx
, librbd::journal::RenameEvent(1, new_image_name
));
592 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
596 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
597 ASSERT_EQ(0, when_acquired_lock(ictx
));
600 int64_t current_entry
;
601 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
602 ASSERT_EQ(initial_tag
+ 1, current_tag
);
603 ASSERT_EQ(1, current_entry
);
605 // verify lock ordering constraints
607 ASSERT_EQ(0, rbd
.rename(m_ioctx
, new_image_name
.c_str(), m_image_name
.c_str()));
610 TEST_F(TestJournalReplay
, Resize
) {
611 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
613 librbd::ImageCtx
*ictx
;
615 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
616 ASSERT_EQ(0, when_acquired_lock(ictx
));
618 // get current commit position
620 int64_t initial_entry
;
621 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
623 // inject snapshot ops into journal
624 inject_into_journal(ictx
, librbd::journal::ResizeEvent(1, 16));
625 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
629 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
630 ASSERT_EQ(0, when_acquired_lock(ictx
));
633 int64_t current_entry
;
634 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
635 ASSERT_EQ(initial_tag
+ 1, current_tag
);
636 ASSERT_EQ(1, current_entry
);
638 // verify lock ordering constraints
639 librbd::NoOpProgressContext no_op_progress
;
640 ASSERT_EQ(0, ictx
->operations
->resize(0, true, no_op_progress
));
643 TEST_F(TestJournalReplay
, Flatten
) {
644 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
| RBD_FEATURE_JOURNALING
);
646 librbd::ImageCtx
*ictx
;
647 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
648 ASSERT_EQ(0, ictx
->operations
->snap_create(cls::rbd::UserSnapshotNamespace(),
650 ASSERT_EQ(0, ictx
->operations
->snap_protect(cls::rbd::UserSnapshotNamespace(),
653 std::string clone_name
= get_temp_image_name();
654 int order
= ictx
->order
;
655 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap", m_ioctx
,
656 clone_name
.c_str(), ictx
->features
, &order
, 0, 0));
658 librbd::ImageCtx
*ictx2
;
659 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
660 ASSERT_EQ(0, when_acquired_lock(ictx2
));
662 // get current commit position
664 int64_t initial_entry
;
665 get_journal_commit_position(ictx2
, &initial_tag
, &initial_entry
);
667 // inject snapshot ops into journal
668 inject_into_journal(ictx2
, librbd::journal::FlattenEvent(1));
669 inject_into_journal(ictx2
, librbd::journal::OpFinishEvent(1, 0));
673 ASSERT_EQ(0, open_image(clone_name
, &ictx2
));
674 ASSERT_EQ(0, when_acquired_lock(ictx2
));
677 int64_t current_entry
;
678 get_journal_commit_position(ictx2
, ¤t_tag
, ¤t_entry
);
679 ASSERT_EQ(initial_tag
+ 1, current_tag
);
680 ASSERT_EQ(1, current_entry
);
681 ASSERT_EQ(0, ictx
->operations
->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
684 // verify lock ordering constraints
685 librbd::NoOpProgressContext no_op
;
686 ASSERT_EQ(-EINVAL
, ictx2
->operations
->flatten(no_op
));
689 TEST_F(TestJournalReplay
, UpdateFeatures
) {
690 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
692 librbd::ImageCtx
*ictx
;
694 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
695 ASSERT_EQ(0, when_acquired_lock(ictx
));
697 uint64_t features
= RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
;
698 bool enabled
= !ictx
->test_features(features
);
700 // get current commit position
702 int64_t initial_entry
;
703 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
705 // inject update_features op into journal
706 inject_into_journal(ictx
, librbd::journal::UpdateFeaturesEvent(1, features
,
711 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
712 ASSERT_EQ(0, when_acquired_lock(ictx
));
715 int64_t current_entry
;
716 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
717 ASSERT_EQ(initial_tag
+ 1, current_tag
);
718 ASSERT_EQ(0, current_entry
);
720 ASSERT_EQ(enabled
, ictx
->test_features(features
));
722 // verify lock ordering constraints
723 ASSERT_EQ(0, ictx
->operations
->update_features(features
, !enabled
));
726 TEST_F(TestJournalReplay
, MetadataSet
) {
727 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
729 librbd::ImageCtx
*ictx
;
731 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
732 ASSERT_EQ(0, when_acquired_lock(ictx
));
734 // get current commit position
736 int64_t initial_entry
;
737 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
739 // inject metadata_set op into journal
740 inject_into_journal(ictx
, librbd::journal::MetadataSetEvent(1, "key", "value"));
741 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
745 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
746 ASSERT_EQ(0, when_acquired_lock(ictx
));
749 int64_t current_entry
;
750 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
751 ASSERT_EQ(initial_tag
+ 1, current_tag
);
752 ASSERT_EQ(1, current_entry
);
755 ASSERT_EQ(0, librbd::metadata_get(ictx
, "key", &value
));
756 ASSERT_EQ("value", value
);
758 // verify lock ordering constraints
759 ASSERT_EQ(0, ictx
->operations
->metadata_set("key2", "value"));
762 TEST_F(TestJournalReplay
, MetadataRemove
) {
763 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
765 librbd::ImageCtx
*ictx
;
767 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
768 ASSERT_EQ(0, when_acquired_lock(ictx
));
770 ASSERT_EQ(0, ictx
->operations
->metadata_set("key", "value"));
772 // get current commit position
774 int64_t initial_entry
;
775 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
777 // inject metadata_remove op into journal
778 inject_into_journal(ictx
, librbd::journal::MetadataRemoveEvent(1, "key"));
779 inject_into_journal(ictx
, librbd::journal::OpFinishEvent(1, 0));
783 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
784 ASSERT_EQ(0, when_acquired_lock(ictx
));
787 int64_t current_entry
;
788 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
789 ASSERT_EQ(initial_tag
, current_tag
);
790 ASSERT_EQ(initial_entry
+ 2, current_entry
);
793 ASSERT_EQ(-ENOENT
, librbd::metadata_get(ictx
, "key", &value
));
795 // verify lock ordering constraints
796 ASSERT_EQ(0, ictx
->operations
->metadata_set("key", "value"));
797 ASSERT_EQ(0, ictx
->operations
->metadata_remove("key"));
800 TEST_F(TestJournalReplay
, ObjectPosition
) {
801 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING
);
803 librbd::ImageCtx
*ictx
;
804 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
805 ASSERT_EQ(0, when_acquired_lock(ictx
));
807 // get current commit position
809 int64_t initial_entry
;
810 get_journal_commit_position(ictx
, &initial_tag
, &initial_entry
);
812 std::string
payload(4096, '1');
813 bufferlist payload_bl
;
814 payload_bl
.append(payload
);
815 auto aio_comp
= new librbd::io::AioCompletion();
816 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
817 bufferlist
{payload_bl
}, 0);
818 ASSERT_EQ(0, aio_comp
->wait_for_complete());
821 aio_comp
= new librbd::io::AioCompletion();
822 ictx
->io_work_queue
->aio_flush(aio_comp
);
823 ASSERT_EQ(0, aio_comp
->wait_for_complete());
826 // check the commit position updated
828 int64_t current_entry
;
829 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
830 ASSERT_EQ(initial_tag
+ 1, current_tag
);
831 ASSERT_EQ(1, current_entry
);
835 aio_comp
= new librbd::io::AioCompletion();
836 ictx
->io_work_queue
->aio_write(aio_comp
, 0, payload
.size(),
837 bufferlist
{payload_bl
}, 0);
838 ASSERT_EQ(0, aio_comp
->wait_for_complete());
841 aio_comp
= new librbd::io::AioCompletion();
842 ictx
->io_work_queue
->aio_flush(aio_comp
);
843 ASSERT_EQ(0, aio_comp
->wait_for_complete());
847 // user flush requests are ignored when journaling + cache are enabled
848 RWLock::RLocker
owner_lock(ictx
->owner_lock
);
852 // check the commit position updated
853 get_journal_commit_position(ictx
, ¤t_tag
, ¤t_entry
);
854 ASSERT_EQ(initial_tag
+ 1, current_tag
);
855 ASSERT_EQ(3, current_entry
);