]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "test/librbd/test_mock_fixture.h" | |
5 | #include "test/librbd/test_support.h" | |
6 | #include "test/librbd/mock/MockImageCtx.h" | |
7 | #include "librbd/io/ImageRequest.h" | |
8 | #include "librbd/journal/Replay.h" | |
9 | #include "librbd/journal/Types.h" | |
10 | #include "gmock/gmock.h" | |
11 | #include "gtest/gtest.h" | |
12 | #include <boost/scope_exit.hpp> | |
13 | ||
14 | namespace librbd { | |
15 | ||
16 | namespace { | |
17 | ||
18 | struct MockReplayImageCtx : public MockImageCtx { | |
19 | MockReplayImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) { | |
20 | } | |
21 | }; | |
22 | ||
23 | } // anonymous namespace | |
24 | ||
25 | namespace io { | |
26 | ||
27 | template <> | |
28 | struct ImageRequest<MockReplayImageCtx> { | |
29 | static ImageRequest *s_instance; | |
30 | ||
31 | MOCK_METHOD4(aio_write, void(AioCompletion *c, const Extents &image_extents, | |
32 | const bufferlist &bl, int op_flags)); | |
33 | static void aio_write(MockReplayImageCtx *ictx, AioCompletion *c, | |
34 | Extents &&image_extents, bufferlist &&bl, | |
35 | int op_flags) { | |
36 | assert(s_instance != nullptr); | |
37 | s_instance->aio_write(c, image_extents, bl, op_flags); | |
38 | } | |
39 | ||
40 | MOCK_METHOD4(aio_discard, void(AioCompletion *c, uint64_t off, uint64_t len, | |
41 | bool skip_partial_discard)); | |
42 | static void aio_discard(MockReplayImageCtx *ictx, AioCompletion *c, | |
43 | uint64_t off, uint64_t len, bool skip_partial_discard) { | |
44 | assert(s_instance != nullptr); | |
45 | s_instance->aio_discard(c, off, len, skip_partial_discard); | |
46 | } | |
47 | ||
48 | MOCK_METHOD1(aio_flush, void(AioCompletion *c)); | |
49 | static void aio_flush(MockReplayImageCtx *ictx, AioCompletion *c) { | |
50 | assert(s_instance != nullptr); | |
51 | s_instance->aio_flush(c); | |
52 | } | |
53 | ||
54 | MOCK_METHOD5(aio_writesame, void(AioCompletion *c, uint64_t off, uint64_t len, | |
55 | const bufferlist &bl, int op_flags)); | |
56 | static void aio_writesame(MockReplayImageCtx *ictx, AioCompletion *c, | |
57 | uint64_t off, uint64_t len, bufferlist &&bl, | |
58 | int op_flags) { | |
59 | assert(s_instance != nullptr); | |
60 | s_instance->aio_writesame(c, off, len, bl, op_flags); | |
61 | } | |
62 | ||
63 | ImageRequest() { | |
64 | s_instance = this; | |
65 | } | |
66 | }; | |
67 | ||
68 | ImageRequest<MockReplayImageCtx> *ImageRequest<MockReplayImageCtx>::s_instance = nullptr; | |
69 | ||
70 | } // namespace io | |
71 | ||
72 | namespace util { | |
73 | ||
74 | inline ImageCtx *get_image_ctx(librbd::MockReplayImageCtx *image_ctx) { | |
75 | return image_ctx->image_ctx; | |
76 | } | |
77 | ||
78 | } // namespace util | |
79 | ||
80 | } // namespace librbd | |
81 | ||
82 | // template definitions | |
83 | #include "librbd/journal/Replay.cc" | |
84 | template class librbd::journal::Replay<librbd::MockReplayImageCtx>; | |
85 | ||
86 | using ::testing::_; | |
87 | using ::testing::DoAll; | |
88 | using ::testing::InSequence; | |
89 | using ::testing::Return; | |
90 | using ::testing::SaveArg; | |
91 | using ::testing::StrEq; | |
92 | using ::testing::WithArgs; | |
93 | ||
94 | MATCHER_P(BufferlistEqual, str, "") { | |
95 | bufferlist bl(arg); | |
96 | return (strncmp(bl.c_str(), str, strlen(str)) == 0); | |
97 | } | |
98 | ||
99 | MATCHER_P(CStrEq, str, "") { | |
100 | return (strncmp(arg, str, strlen(str)) == 0); | |
101 | } | |
102 | ||
103 | ACTION_P2(NotifyInvoke, lock, cond) { | |
104 | Mutex::Locker locker(*lock); | |
105 | cond->Signal(); | |
106 | } | |
107 | ||
108 | ACTION_P2(CompleteAioCompletion, r, image_ctx) { | |
109 | image_ctx->op_work_queue->queue(new FunctionContext([this, arg0](int r) { | |
110 | arg0->get(); | |
111 | arg0->init_time(image_ctx, librbd::io::AIO_TYPE_NONE); | |
112 | arg0->set_request_count(1); | |
113 | arg0->complete_request(r); | |
114 | }), r); | |
115 | } | |
116 | ||
117 | namespace librbd { | |
118 | namespace journal { | |
119 | ||
120 | class TestMockJournalReplay : public TestMockFixture { | |
121 | public: | |
122 | typedef io::ImageRequest<MockReplayImageCtx> MockIoImageRequest; | |
123 | typedef Replay<MockReplayImageCtx> MockJournalReplay; | |
124 | ||
125 | TestMockJournalReplay() : m_invoke_lock("m_invoke_lock") { | |
126 | } | |
127 | ||
128 | void expect_aio_discard(MockIoImageRequest &mock_io_image_request, | |
129 | io::AioCompletion **aio_comp, uint64_t off, | |
130 | uint64_t len, bool skip_partial_discard) { | |
131 | EXPECT_CALL(mock_io_image_request, aio_discard(_, off, len, skip_partial_discard)) | |
132 | .WillOnce(SaveArg<0>(aio_comp)); | |
133 | } | |
134 | ||
135 | void expect_aio_flush(MockIoImageRequest &mock_io_image_request, | |
136 | io::AioCompletion **aio_comp) { | |
137 | EXPECT_CALL(mock_io_image_request, aio_flush(_)) | |
138 | .WillOnce(SaveArg<0>(aio_comp)); | |
139 | } | |
140 | ||
141 | void expect_aio_flush(MockReplayImageCtx &mock_image_ctx, | |
142 | MockIoImageRequest &mock_io_image_request, int r) { | |
143 | EXPECT_CALL(mock_io_image_request, aio_flush(_)) | |
144 | .WillOnce(CompleteAioCompletion(r, mock_image_ctx.image_ctx)); | |
145 | } | |
146 | ||
147 | void expect_aio_write(MockIoImageRequest &mock_io_image_request, | |
148 | io::AioCompletion **aio_comp, uint64_t off, | |
149 | uint64_t len, const char *data) { | |
150 | EXPECT_CALL(mock_io_image_request, | |
151 | aio_write(_, io::Extents{{off, len}}, BufferlistEqual(data), _)) | |
152 | .WillOnce(SaveArg<0>(aio_comp)); | |
153 | } | |
154 | ||
155 | void expect_aio_writesame(MockIoImageRequest &mock_io_image_request, | |
156 | io::AioCompletion **aio_comp, uint64_t off, | |
157 | uint64_t len, const char *data) { | |
158 | EXPECT_CALL(mock_io_image_request, | |
159 | aio_writesame(_, off, len, BufferlistEqual(data), _)) | |
160 | .WillOnce(SaveArg<0>(aio_comp)); | |
161 | } | |
162 | ||
163 | void expect_flatten(MockReplayImageCtx &mock_image_ctx, Context **on_finish) { | |
164 | EXPECT_CALL(*mock_image_ctx.operations, execute_flatten(_, _)) | |
165 | .WillOnce(DoAll(SaveArg<1>(on_finish), | |
166 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
167 | } | |
168 | ||
169 | void expect_rename(MockReplayImageCtx &mock_image_ctx, Context **on_finish, | |
170 | const char *image_name) { | |
171 | EXPECT_CALL(*mock_image_ctx.operations, execute_rename(StrEq(image_name), _)) | |
172 | .WillOnce(DoAll(SaveArg<1>(on_finish), | |
173 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
174 | } | |
175 | ||
176 | void expect_resize(MockReplayImageCtx &mock_image_ctx, Context **on_finish, | |
177 | uint64_t size, uint64_t op_tid) { | |
178 | EXPECT_CALL(*mock_image_ctx.operations, execute_resize(size, _, _, _, op_tid)) | |
179 | .WillOnce(DoAll(SaveArg<3>(on_finish), | |
180 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
181 | } | |
182 | ||
183 | void expect_snap_create(MockReplayImageCtx &mock_image_ctx, | |
184 | Context **on_finish, const char *snap_name, | |
185 | uint64_t op_tid) { | |
186 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_create(_, StrEq(snap_name), _, | |
187 | op_tid, false)) | |
188 | .WillOnce(DoAll(SaveArg<2>(on_finish), | |
189 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
190 | } | |
191 | ||
192 | void expect_snap_remove(MockReplayImageCtx &mock_image_ctx, | |
193 | Context **on_finish, const char *snap_name) { | |
194 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_remove(_, StrEq(snap_name), _)) | |
195 | .WillOnce(DoAll(SaveArg<2>(on_finish), | |
196 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
197 | } | |
198 | ||
199 | void expect_snap_rename(MockReplayImageCtx &mock_image_ctx, | |
200 | Context **on_finish, uint64_t snap_id, | |
201 | const char *snap_name) { | |
202 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_rename(snap_id, StrEq(snap_name), _)) | |
203 | .WillOnce(DoAll(SaveArg<2>(on_finish), | |
204 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
205 | } | |
206 | ||
207 | void expect_snap_protect(MockReplayImageCtx &mock_image_ctx, | |
208 | Context **on_finish, const char *snap_name) { | |
209 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_protect(_, StrEq(snap_name), _)) | |
210 | .WillOnce(DoAll(SaveArg<2>(on_finish), | |
211 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
212 | } | |
213 | ||
214 | void expect_snap_unprotect(MockReplayImageCtx &mock_image_ctx, | |
215 | Context **on_finish, const char *snap_name) { | |
216 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_unprotect(_, StrEq(snap_name), _)) | |
217 | .WillOnce(DoAll(SaveArg<2>(on_finish), | |
218 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
219 | } | |
220 | ||
221 | void expect_snap_rollback(MockReplayImageCtx &mock_image_ctx, | |
222 | Context **on_finish, const char *snap_name) { | |
223 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_rollback(_, StrEq(snap_name), _, _)) | |
224 | .WillOnce(DoAll(SaveArg<3>(on_finish), | |
225 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
226 | } | |
227 | ||
228 | void expect_update_features(MockReplayImageCtx &mock_image_ctx, Context **on_finish, | |
229 | uint64_t features, bool enabled, uint64_t op_tid) { | |
230 | EXPECT_CALL(*mock_image_ctx.operations, execute_update_features(features, enabled, _, op_tid)) | |
231 | .WillOnce(DoAll(SaveArg<2>(on_finish), | |
232 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
233 | } | |
234 | ||
235 | void expect_metadata_set(MockReplayImageCtx &mock_image_ctx, | |
236 | Context **on_finish, const char *key, | |
237 | const char *value) { | |
238 | EXPECT_CALL(*mock_image_ctx.operations, execute_metadata_set(StrEq(key), | |
239 | StrEq(value), _)) | |
240 | .WillOnce(DoAll(SaveArg<2>(on_finish), | |
241 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
242 | } | |
243 | ||
244 | void expect_metadata_remove(MockReplayImageCtx &mock_image_ctx, | |
245 | Context **on_finish, const char *key) { | |
246 | EXPECT_CALL(*mock_image_ctx.operations, execute_metadata_remove(StrEq(key), _)) | |
247 | .WillOnce(DoAll(SaveArg<1>(on_finish), | |
248 | NotifyInvoke(&m_invoke_lock, &m_invoke_cond))); | |
249 | } | |
250 | ||
251 | void expect_refresh_image(MockReplayImageCtx &mock_image_ctx, bool required, | |
252 | int r) { | |
253 | EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()) | |
254 | .WillOnce(Return(required)); | |
255 | if (required) { | |
256 | EXPECT_CALL(*mock_image_ctx.state, refresh(_)) | |
257 | .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); | |
258 | } | |
259 | } | |
260 | ||
261 | void when_process(MockJournalReplay &mock_journal_replay, | |
262 | EventEntry &&event_entry, Context *on_ready, | |
263 | Context *on_safe) { | |
264 | bufferlist bl; | |
265 | ::encode(event_entry, bl); | |
266 | ||
267 | bufferlist::iterator it = bl.begin(); | |
268 | when_process(mock_journal_replay, &it, on_ready, on_safe); | |
269 | } | |
270 | ||
271 | void when_process(MockJournalReplay &mock_journal_replay, | |
272 | bufferlist::iterator *it, Context *on_ready, | |
273 | Context *on_safe) { | |
274 | EventEntry event_entry; | |
275 | int r = mock_journal_replay.decode(it, &event_entry); | |
276 | ASSERT_EQ(0, r); | |
277 | ||
278 | mock_journal_replay.process(event_entry, on_ready, on_safe); | |
279 | } | |
280 | ||
281 | void when_complete(MockReplayImageCtx &mock_image_ctx, | |
282 | io::AioCompletion *aio_comp, int r) { | |
283 | aio_comp->get(); | |
284 | aio_comp->init_time(mock_image_ctx.image_ctx, librbd::io::AIO_TYPE_NONE); | |
285 | aio_comp->set_request_count(1); | |
286 | aio_comp->complete_request(r); | |
287 | } | |
288 | ||
289 | int when_flush(MockJournalReplay &mock_journal_replay) { | |
290 | C_SaferCond ctx; | |
291 | mock_journal_replay.flush(&ctx); | |
292 | return ctx.wait(); | |
293 | } | |
294 | ||
295 | int when_shut_down(MockJournalReplay &mock_journal_replay, bool cancel_ops) { | |
296 | C_SaferCond ctx; | |
297 | mock_journal_replay.shut_down(cancel_ops, &ctx); | |
298 | return ctx.wait(); | |
299 | } | |
300 | ||
301 | void when_replay_op_ready(MockJournalReplay &mock_journal_replay, | |
302 | uint64_t op_tid, Context *on_resume) { | |
303 | mock_journal_replay.replay_op_ready(op_tid, on_resume); | |
304 | } | |
305 | ||
306 | void wait_for_op_invoked(Context **on_finish, int r) { | |
307 | { | |
308 | Mutex::Locker locker(m_invoke_lock); | |
309 | while (*on_finish == nullptr) { | |
310 | m_invoke_cond.Wait(m_invoke_lock); | |
311 | } | |
312 | } | |
313 | (*on_finish)->complete(r); | |
314 | } | |
315 | ||
316 | bufferlist to_bl(const std::string &str) { | |
317 | bufferlist bl; | |
318 | bl.append(str); | |
319 | return bl; | |
320 | } | |
321 | ||
322 | Mutex m_invoke_lock; | |
323 | Cond m_invoke_cond; | |
324 | }; | |
325 | ||
326 | TEST_F(TestMockJournalReplay, AioDiscard) { | |
327 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
328 | ||
329 | librbd::ImageCtx *ictx; | |
330 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
331 | ||
332 | MockReplayImageCtx mock_image_ctx(*ictx); | |
333 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
334 | MockIoImageRequest mock_io_image_request; | |
335 | expect_op_work_queue(mock_image_ctx); | |
336 | ||
337 | InSequence seq; | |
338 | io::AioCompletion *aio_comp; | |
339 | C_SaferCond on_ready; | |
340 | C_SaferCond on_safe; | |
341 | expect_aio_discard(mock_io_image_request, &aio_comp, 123, 456, ictx->skip_partial_discard); | |
342 | when_process(mock_journal_replay, | |
343 | EventEntry{AioDiscardEvent(123, 456, ictx->skip_partial_discard)}, | |
344 | &on_ready, &on_safe); | |
345 | ||
346 | when_complete(mock_image_ctx, aio_comp, 0); | |
347 | ASSERT_EQ(0, on_ready.wait()); | |
348 | ||
349 | expect_aio_flush(mock_image_ctx, mock_io_image_request, 0); | |
350 | ASSERT_EQ(0, when_shut_down(mock_journal_replay, false)); | |
351 | ASSERT_EQ(0, on_safe.wait()); | |
352 | } | |
353 | ||
354 | TEST_F(TestMockJournalReplay, AioWrite) { | |
355 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
356 | ||
357 | librbd::ImageCtx *ictx; | |
358 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
359 | ||
360 | MockReplayImageCtx mock_image_ctx(*ictx); | |
361 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
362 | MockIoImageRequest mock_io_image_request; | |
363 | expect_op_work_queue(mock_image_ctx); | |
364 | ||
365 | InSequence seq; | |
366 | io::AioCompletion *aio_comp; | |
367 | C_SaferCond on_ready; | |
368 | C_SaferCond on_safe; | |
369 | expect_aio_write(mock_io_image_request, &aio_comp, 123, 456, "test"); | |
370 | when_process(mock_journal_replay, | |
371 | EventEntry{AioWriteEvent(123, 456, to_bl("test"))}, | |
372 | &on_ready, &on_safe); | |
373 | ||
374 | when_complete(mock_image_ctx, aio_comp, 0); | |
375 | ASSERT_EQ(0, on_ready.wait()); | |
376 | ||
377 | expect_aio_flush(mock_image_ctx, mock_io_image_request, 0); | |
378 | ASSERT_EQ(0, when_shut_down(mock_journal_replay, false)); | |
379 | ASSERT_EQ(0, on_safe.wait()); | |
380 | } | |
381 | ||
382 | TEST_F(TestMockJournalReplay, AioFlush) { | |
383 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
384 | ||
385 | librbd::ImageCtx *ictx; | |
386 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
387 | ||
388 | MockReplayImageCtx mock_image_ctx(*ictx); | |
389 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
390 | MockIoImageRequest mock_io_image_request; | |
391 | expect_op_work_queue(mock_image_ctx); | |
392 | ||
393 | InSequence seq; | |
394 | io::AioCompletion *aio_comp; | |
395 | C_SaferCond on_ready; | |
396 | C_SaferCond on_safe; | |
397 | expect_aio_flush(mock_io_image_request, &aio_comp); | |
398 | when_process(mock_journal_replay, EventEntry{AioFlushEvent()}, | |
399 | &on_ready, &on_safe); | |
400 | ||
401 | when_complete(mock_image_ctx, aio_comp, 0); | |
402 | ASSERT_EQ(0, on_safe.wait()); | |
403 | ||
404 | ASSERT_EQ(0, when_shut_down(mock_journal_replay, false)); | |
405 | ASSERT_EQ(0, on_ready.wait()); | |
406 | } | |
407 | ||
408 | TEST_F(TestMockJournalReplay, AioWriteSame) { | |
409 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
410 | ||
411 | librbd::ImageCtx *ictx; | |
412 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
413 | ||
414 | MockReplayImageCtx mock_image_ctx(*ictx); | |
415 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
416 | MockIoImageRequest mock_io_image_request; | |
417 | expect_op_work_queue(mock_image_ctx); | |
418 | ||
419 | InSequence seq; | |
420 | io::AioCompletion *aio_comp; | |
421 | C_SaferCond on_ready; | |
422 | C_SaferCond on_safe; | |
423 | expect_aio_writesame(mock_io_image_request, &aio_comp, 123, 456, "333"); | |
424 | when_process(mock_journal_replay, | |
425 | EventEntry{AioWriteSameEvent(123, 456, to_bl("333"))}, | |
426 | &on_ready, &on_safe); | |
427 | ||
428 | when_complete(mock_image_ctx, aio_comp, 0); | |
429 | ASSERT_EQ(0, on_ready.wait()); | |
430 | ||
431 | expect_aio_flush(mock_image_ctx, mock_io_image_request, 0); | |
432 | ASSERT_EQ(0, when_shut_down(mock_journal_replay, false)); | |
433 | ASSERT_EQ(0, on_safe.wait()); | |
434 | } | |
435 | ||
436 | TEST_F(TestMockJournalReplay, IOError) { | |
437 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
438 | ||
439 | librbd::ImageCtx *ictx; | |
440 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
441 | ||
442 | MockReplayImageCtx mock_image_ctx(*ictx); | |
443 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
444 | MockIoImageRequest mock_io_image_request; | |
445 | expect_op_work_queue(mock_image_ctx); | |
446 | ||
447 | InSequence seq; | |
448 | io::AioCompletion *aio_comp; | |
449 | C_SaferCond on_ready; | |
450 | C_SaferCond on_safe; | |
451 | expect_aio_discard(mock_io_image_request, &aio_comp, 123, 456, ictx->skip_partial_discard); | |
452 | when_process(mock_journal_replay, | |
453 | EventEntry{AioDiscardEvent(123, 456, ictx->skip_partial_discard)}, | |
454 | &on_ready, &on_safe); | |
455 | ||
456 | when_complete(mock_image_ctx, aio_comp, -EINVAL); | |
457 | ASSERT_EQ(-EINVAL, on_safe.wait()); | |
458 | ||
459 | expect_aio_flush(mock_image_ctx, mock_io_image_request, 0); | |
460 | ASSERT_EQ(0, when_shut_down(mock_journal_replay, false)); | |
461 | ASSERT_EQ(0, on_ready.wait()); | |
462 | } | |
463 | ||
464 | TEST_F(TestMockJournalReplay, SoftFlushIO) { | |
465 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
466 | ||
467 | librbd::ImageCtx *ictx; | |
468 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
469 | ||
470 | MockReplayImageCtx mock_image_ctx(*ictx); | |
471 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
472 | MockIoImageRequest mock_io_image_request; | |
473 | expect_op_work_queue(mock_image_ctx); | |
474 | ||
475 | InSequence seq; | |
476 | const size_t io_count = 32; | |
477 | C_SaferCond on_safes[io_count]; | |
478 | for (size_t i = 0; i < io_count; ++i) { | |
479 | io::AioCompletion *aio_comp; | |
480 | io::AioCompletion *flush_comp = nullptr; | |
481 | C_SaferCond on_ready; | |
482 | expect_aio_discard(mock_io_image_request, &aio_comp, 123, 456, ictx->skip_partial_discard); | |
483 | if (i == io_count - 1) { | |
484 | expect_aio_flush(mock_io_image_request, &flush_comp); | |
485 | } | |
486 | when_process(mock_journal_replay, | |
487 | EventEntry{AioDiscardEvent(123, 456, ictx->skip_partial_discard)}, | |
488 | &on_ready, &on_safes[i]); | |
489 | when_complete(mock_image_ctx, aio_comp, 0); | |
490 | ASSERT_EQ(0, on_ready.wait()); | |
491 | ||
492 | if (flush_comp != nullptr) { | |
493 | when_complete(mock_image_ctx, flush_comp, 0); | |
494 | } | |
495 | } | |
496 | for (auto &on_safe : on_safes) { | |
497 | ASSERT_EQ(0, on_safe.wait()); | |
498 | } | |
499 | ||
500 | ASSERT_EQ(0, when_shut_down(mock_journal_replay, false)); | |
501 | } | |
502 | ||
503 | TEST_F(TestMockJournalReplay, PauseIO) { | |
504 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
505 | ||
506 | librbd::ImageCtx *ictx; | |
507 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
508 | ||
509 | MockReplayImageCtx mock_image_ctx(*ictx); | |
510 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
511 | MockIoImageRequest mock_io_image_request; | |
512 | expect_op_work_queue(mock_image_ctx); | |
513 | ||
514 | InSequence seq; | |
515 | const size_t io_count = 64; | |
516 | std::list<io::AioCompletion *> flush_comps; | |
517 | C_SaferCond on_safes[io_count]; | |
518 | for (size_t i = 0; i < io_count; ++i) { | |
519 | io::AioCompletion *aio_comp; | |
520 | C_SaferCond on_ready; | |
521 | expect_aio_write(mock_io_image_request, &aio_comp, 123, 456, "test"); | |
522 | if ((i + 1) % 32 == 0) { | |
523 | flush_comps.push_back(nullptr); | |
524 | expect_aio_flush(mock_io_image_request, &flush_comps.back()); | |
525 | } | |
526 | when_process(mock_journal_replay, | |
527 | EventEntry{AioWriteEvent(123, 456, to_bl("test"))}, | |
528 | &on_ready, &on_safes[i]); | |
529 | when_complete(mock_image_ctx, aio_comp, 0); | |
530 | if (i < io_count - 1) { | |
531 | ASSERT_EQ(0, on_ready.wait()); | |
532 | } else { | |
533 | for (auto flush_comp : flush_comps) { | |
534 | when_complete(mock_image_ctx, flush_comp, 0); | |
535 | } | |
536 | ASSERT_EQ(0, on_ready.wait()); | |
537 | } | |
538 | } | |
539 | for (auto &on_safe : on_safes) { | |
540 | ASSERT_EQ(0, on_safe.wait()); | |
541 | } | |
542 | ||
543 | ASSERT_EQ(0, when_shut_down(mock_journal_replay, false)); | |
544 | } | |
545 | ||
546 | TEST_F(TestMockJournalReplay, Flush) { | |
547 | librbd::ImageCtx *ictx; | |
548 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
549 | ||
550 | MockReplayImageCtx mock_image_ctx(*ictx); | |
551 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
552 | MockIoImageRequest mock_io_image_request; | |
553 | expect_op_work_queue(mock_image_ctx); | |
554 | ||
555 | InSequence seq; | |
556 | io::AioCompletion *aio_comp = nullptr; | |
557 | C_SaferCond on_ready; | |
558 | C_SaferCond on_safe; | |
559 | expect_aio_discard(mock_io_image_request, &aio_comp, 123, 456, ictx->skip_partial_discard); | |
560 | when_process(mock_journal_replay, | |
561 | EventEntry{AioDiscardEvent(123, 456, ictx->skip_partial_discard)}, | |
562 | &on_ready, &on_safe); | |
563 | ||
564 | when_complete(mock_image_ctx, aio_comp, 0); | |
565 | ASSERT_EQ(0, on_ready.wait()); | |
566 | ||
567 | expect_aio_flush(mock_image_ctx, mock_io_image_request, 0); | |
568 | ASSERT_EQ(0, when_flush(mock_journal_replay)); | |
569 | ASSERT_EQ(0, on_safe.wait()); | |
570 | } | |
571 | ||
572 | TEST_F(TestMockJournalReplay, OpFinishError) { | |
573 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
574 | ||
575 | librbd::ImageCtx *ictx; | |
576 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
577 | ||
578 | MockReplayImageCtx mock_image_ctx(*ictx); | |
579 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
580 | expect_op_work_queue(mock_image_ctx); | |
581 | ||
582 | InSequence seq; | |
583 | C_SaferCond on_start_ready; | |
584 | C_SaferCond on_start_safe; | |
585 | when_process(mock_journal_replay, | |
586 | EventEntry{SnapRemoveEvent(123, | |
587 | cls::rbd::UserSnapshotNamespace(), | |
588 | "snap")}, | |
589 | &on_start_ready, | |
590 | &on_start_safe); | |
591 | ASSERT_EQ(0, on_start_ready.wait()); | |
592 | ||
593 | C_SaferCond on_finish_ready; | |
594 | C_SaferCond on_finish_safe; | |
595 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, -EIO)}, | |
596 | &on_finish_ready, &on_finish_safe); | |
597 | ||
598 | ASSERT_EQ(-EIO, on_start_safe.wait()); | |
599 | ASSERT_EQ(-EIO, on_finish_safe.wait()); | |
600 | ASSERT_EQ(0, on_finish_ready.wait()); | |
601 | } | |
602 | ||
603 | TEST_F(TestMockJournalReplay, BlockedOpFinishError) { | |
604 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
605 | ||
606 | librbd::ImageCtx *ictx; | |
607 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
608 | ||
609 | MockReplayImageCtx mock_image_ctx(*ictx); | |
610 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
611 | expect_op_work_queue(mock_image_ctx); | |
612 | ||
613 | InSequence seq; | |
614 | Context *on_finish = nullptr; | |
615 | expect_refresh_image(mock_image_ctx, false, 0); | |
616 | expect_snap_create(mock_image_ctx, &on_finish, "snap", 123); | |
617 | ||
618 | C_SaferCond on_start_ready; | |
619 | C_SaferCond on_start_safe; | |
620 | when_process(mock_journal_replay, | |
621 | EventEntry{SnapCreateEvent(123, | |
622 | cls::rbd::UserSnapshotNamespace(), | |
623 | "snap")}, | |
624 | &on_start_ready, | |
625 | &on_start_safe); | |
626 | ||
627 | C_SaferCond on_resume; | |
628 | when_replay_op_ready(mock_journal_replay, 123, &on_resume); | |
629 | ASSERT_EQ(0, on_start_ready.wait()); | |
630 | ||
631 | C_SaferCond on_finish_ready; | |
632 | C_SaferCond on_finish_safe; | |
633 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, -EBADMSG)}, | |
634 | &on_finish_ready, &on_finish_safe); | |
635 | ||
636 | ASSERT_EQ(-EBADMSG, on_resume.wait()); | |
637 | wait_for_op_invoked(&on_finish, -ESTALE); | |
638 | ||
639 | ASSERT_EQ(-ESTALE, on_start_safe.wait()); | |
640 | ASSERT_EQ(-ESTALE, on_finish_safe.wait()); | |
641 | ASSERT_EQ(0, on_finish_ready.wait()); | |
642 | } | |
643 | ||
644 | TEST_F(TestMockJournalReplay, MissingOpFinishEvent) { | |
645 | librbd::ImageCtx *ictx; | |
646 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
647 | ||
648 | MockReplayImageCtx mock_image_ctx(*ictx); | |
649 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
650 | expect_op_work_queue(mock_image_ctx); | |
651 | ||
652 | EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()) | |
653 | .WillRepeatedly(Return(false)); | |
654 | ||
655 | InSequence seq; | |
656 | Context *on_snap_create_finish = nullptr; | |
657 | expect_snap_create(mock_image_ctx, &on_snap_create_finish, "snap", 123); | |
658 | ||
659 | Context *on_snap_remove_finish = nullptr; | |
660 | expect_snap_remove(mock_image_ctx, &on_snap_remove_finish, "snap"); | |
661 | ||
662 | C_SaferCond on_snap_remove_ready; | |
663 | C_SaferCond on_snap_remove_safe; | |
664 | when_process(mock_journal_replay, | |
665 | EventEntry{SnapRemoveEvent(122, | |
666 | cls::rbd::UserSnapshotNamespace(), | |
667 | "snap")}, | |
668 | &on_snap_remove_ready, | |
669 | &on_snap_remove_safe); | |
670 | ASSERT_EQ(0, on_snap_remove_ready.wait()); | |
671 | ||
672 | C_SaferCond on_snap_create_ready; | |
673 | C_SaferCond on_snap_create_safe; | |
674 | when_process(mock_journal_replay, | |
675 | EventEntry{SnapCreateEvent(123, | |
676 | cls::rbd::UserSnapshotNamespace(), | |
677 | "snap")}, | |
678 | &on_snap_create_ready, | |
679 | &on_snap_create_safe); | |
680 | ||
681 | C_SaferCond on_shut_down; | |
682 | mock_journal_replay.shut_down(false, &on_shut_down); | |
683 | ||
684 | wait_for_op_invoked(&on_snap_remove_finish, 0); | |
685 | ASSERT_EQ(0, on_snap_remove_safe.wait()); | |
686 | ||
687 | C_SaferCond on_snap_create_resume; | |
688 | when_replay_op_ready(mock_journal_replay, 123, &on_snap_create_resume); | |
689 | ASSERT_EQ(0, on_snap_create_resume.wait()); | |
690 | ||
691 | wait_for_op_invoked(&on_snap_create_finish, 0); | |
692 | ASSERT_EQ(0, on_snap_create_ready.wait()); | |
693 | ASSERT_EQ(0, on_snap_create_safe.wait()); | |
694 | ||
695 | ASSERT_EQ(0, on_shut_down.wait()); | |
696 | } | |
697 | ||
698 | TEST_F(TestMockJournalReplay, MissingOpFinishEventCancelOps) { | |
699 | librbd::ImageCtx *ictx; | |
700 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
701 | ||
702 | MockReplayImageCtx mock_image_ctx(*ictx); | |
703 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
704 | expect_op_work_queue(mock_image_ctx); | |
705 | ||
706 | InSequence seq; | |
707 | Context *on_snap_create_finish = nullptr; | |
708 | expect_refresh_image(mock_image_ctx, false, 0); | |
709 | expect_snap_create(mock_image_ctx, &on_snap_create_finish, "snap", 123); | |
710 | ||
711 | C_SaferCond on_snap_remove_ready; | |
712 | C_SaferCond on_snap_remove_safe; | |
713 | when_process(mock_journal_replay, | |
714 | EventEntry{SnapRemoveEvent(122, | |
715 | cls::rbd::UserSnapshotNamespace(), | |
716 | "snap")}, | |
717 | &on_snap_remove_ready, | |
718 | &on_snap_remove_safe); | |
719 | ASSERT_EQ(0, on_snap_remove_ready.wait()); | |
720 | ||
721 | C_SaferCond on_snap_create_ready; | |
722 | C_SaferCond on_snap_create_safe; | |
723 | when_process(mock_journal_replay, | |
724 | EventEntry{SnapCreateEvent(123, | |
725 | cls::rbd::UserSnapshotNamespace(), | |
726 | "snap")}, | |
727 | &on_snap_create_ready, | |
728 | &on_snap_create_safe); | |
729 | ||
730 | C_SaferCond on_resume; | |
731 | when_replay_op_ready(mock_journal_replay, 123, &on_resume); | |
732 | ASSERT_EQ(0, on_snap_create_ready.wait()); | |
733 | ||
734 | C_SaferCond on_shut_down; | |
735 | mock_journal_replay.shut_down(true, &on_shut_down); | |
736 | ||
737 | ASSERT_EQ(-ERESTART, on_resume.wait()); | |
738 | on_snap_create_finish->complete(-ERESTART); | |
739 | ASSERT_EQ(-ERESTART, on_snap_create_safe.wait()); | |
740 | ||
741 | ASSERT_EQ(-ERESTART, on_snap_remove_safe.wait()); | |
742 | ASSERT_EQ(0, on_shut_down.wait()); | |
743 | } | |
744 | ||
745 | TEST_F(TestMockJournalReplay, UnknownOpFinishEvent) { | |
746 | librbd::ImageCtx *ictx; | |
747 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
748 | ||
749 | MockReplayImageCtx mock_image_ctx(*ictx); | |
750 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
751 | expect_op_work_queue(mock_image_ctx); | |
752 | ||
753 | InSequence seq; | |
754 | C_SaferCond on_ready; | |
755 | C_SaferCond on_safe; | |
756 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
757 | &on_ready, &on_safe); | |
758 | ||
759 | ASSERT_EQ(0, on_safe.wait()); | |
760 | ASSERT_EQ(0, on_ready.wait()); | |
761 | } | |
762 | ||
763 | TEST_F(TestMockJournalReplay, OpEventError) { | |
764 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
765 | ||
766 | librbd::ImageCtx *ictx; | |
767 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
768 | ||
769 | MockReplayImageCtx mock_image_ctx(*ictx); | |
770 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
771 | expect_op_work_queue(mock_image_ctx); | |
772 | ||
773 | InSequence seq; | |
774 | Context *on_finish = nullptr; | |
775 | expect_refresh_image(mock_image_ctx, false, 0); | |
776 | expect_snap_remove(mock_image_ctx, &on_finish, "snap"); | |
777 | ||
778 | C_SaferCond on_start_ready; | |
779 | C_SaferCond on_start_safe; | |
780 | when_process(mock_journal_replay, | |
781 | EventEntry{SnapRemoveEvent(123, | |
782 | cls::rbd::UserSnapshotNamespace(), | |
783 | "snap")}, | |
784 | &on_start_ready, | |
785 | &on_start_safe); | |
786 | ASSERT_EQ(0, on_start_ready.wait()); | |
787 | ||
788 | C_SaferCond on_finish_ready; | |
789 | C_SaferCond on_finish_safe; | |
790 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
791 | &on_finish_ready, &on_finish_safe); | |
792 | ||
793 | wait_for_op_invoked(&on_finish, -EINVAL); | |
794 | ASSERT_EQ(-EINVAL, on_start_safe.wait()); | |
795 | ASSERT_EQ(0, on_finish_ready.wait()); | |
796 | ASSERT_EQ(-EINVAL, on_finish_safe.wait()); | |
797 | } | |
798 | ||
799 | TEST_F(TestMockJournalReplay, SnapCreateEvent) { | |
800 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
801 | ||
802 | librbd::ImageCtx *ictx; | |
803 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
804 | ||
805 | MockReplayImageCtx mock_image_ctx(*ictx); | |
806 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
807 | expect_op_work_queue(mock_image_ctx); | |
808 | ||
809 | InSequence seq; | |
810 | Context *on_finish = nullptr; | |
811 | expect_refresh_image(mock_image_ctx, false, 0); | |
812 | expect_snap_create(mock_image_ctx, &on_finish, "snap", 123); | |
813 | ||
814 | C_SaferCond on_start_ready; | |
815 | C_SaferCond on_start_safe; | |
816 | when_process(mock_journal_replay, | |
817 | EventEntry{SnapCreateEvent(123, | |
818 | cls::rbd::UserSnapshotNamespace(), | |
819 | "snap")}, | |
820 | &on_start_ready, | |
821 | &on_start_safe); | |
822 | ||
823 | C_SaferCond on_resume; | |
824 | when_replay_op_ready(mock_journal_replay, 123, &on_resume); | |
825 | ASSERT_EQ(0, on_start_ready.wait()); | |
826 | ||
827 | C_SaferCond on_finish_ready; | |
828 | C_SaferCond on_finish_safe; | |
829 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
830 | &on_finish_ready, &on_finish_safe); | |
831 | ||
832 | ASSERT_EQ(0, on_resume.wait()); | |
833 | wait_for_op_invoked(&on_finish, 0); | |
834 | ||
835 | ASSERT_EQ(0, on_start_safe.wait()); | |
836 | ASSERT_EQ(0, on_finish_ready.wait()); | |
837 | ASSERT_EQ(0, on_finish_safe.wait()); | |
838 | } | |
839 | ||
840 | TEST_F(TestMockJournalReplay, SnapCreateEventExists) { | |
841 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
842 | ||
843 | librbd::ImageCtx *ictx; | |
844 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
845 | ||
846 | MockReplayImageCtx mock_image_ctx(*ictx); | |
847 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
848 | expect_op_work_queue(mock_image_ctx); | |
849 | ||
850 | InSequence seq; | |
851 | Context *on_finish = nullptr; | |
852 | expect_refresh_image(mock_image_ctx, false, 0); | |
853 | expect_snap_create(mock_image_ctx, &on_finish, "snap", 123); | |
854 | ||
855 | C_SaferCond on_start_ready; | |
856 | C_SaferCond on_start_safe; | |
857 | when_process(mock_journal_replay, | |
858 | EventEntry{SnapCreateEvent(123, | |
859 | cls::rbd::UserSnapshotNamespace(), | |
860 | "snap")}, | |
861 | &on_start_ready, | |
862 | &on_start_safe); | |
863 | ||
864 | wait_for_op_invoked(&on_finish, -EEXIST); | |
865 | ASSERT_EQ(0, on_start_ready.wait()); | |
866 | ||
867 | C_SaferCond on_finish_ready; | |
868 | C_SaferCond on_finish_safe; | |
869 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
870 | &on_finish_ready, &on_finish_safe); | |
871 | ||
872 | ASSERT_EQ(0, on_start_safe.wait()); | |
873 | ASSERT_EQ(0, on_finish_ready.wait()); | |
874 | ASSERT_EQ(0, on_finish_safe.wait()); | |
875 | } | |
876 | ||
877 | TEST_F(TestMockJournalReplay, SnapRemoveEvent) { | |
878 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
879 | ||
880 | librbd::ImageCtx *ictx; | |
881 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
882 | ||
883 | MockReplayImageCtx mock_image_ctx(*ictx); | |
884 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
885 | expect_op_work_queue(mock_image_ctx); | |
886 | ||
887 | InSequence seq; | |
888 | Context *on_finish = nullptr; | |
889 | expect_refresh_image(mock_image_ctx, false, 0); | |
890 | expect_snap_remove(mock_image_ctx, &on_finish, "snap"); | |
891 | ||
892 | C_SaferCond on_start_ready; | |
893 | C_SaferCond on_start_safe; | |
894 | when_process(mock_journal_replay, | |
895 | EventEntry{SnapRemoveEvent(123, | |
896 | cls::rbd::UserSnapshotNamespace(), | |
897 | "snap")}, | |
898 | &on_start_ready, | |
899 | &on_start_safe); | |
900 | ASSERT_EQ(0, on_start_ready.wait()); | |
901 | ||
902 | C_SaferCond on_finish_ready; | |
903 | C_SaferCond on_finish_safe; | |
904 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
905 | &on_finish_ready, &on_finish_safe); | |
906 | ||
907 | wait_for_op_invoked(&on_finish, 0); | |
908 | ASSERT_EQ(0, on_start_safe.wait()); | |
909 | ASSERT_EQ(0, on_finish_ready.wait()); | |
910 | ASSERT_EQ(0, on_finish_safe.wait()); | |
911 | } | |
912 | ||
913 | TEST_F(TestMockJournalReplay, SnapRemoveEventDNE) { | |
914 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
915 | ||
916 | librbd::ImageCtx *ictx; | |
917 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
918 | ||
919 | MockReplayImageCtx mock_image_ctx(*ictx); | |
920 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
921 | expect_op_work_queue(mock_image_ctx); | |
922 | ||
923 | InSequence seq; | |
924 | Context *on_finish = nullptr; | |
925 | expect_refresh_image(mock_image_ctx, false, 0); | |
926 | expect_snap_remove(mock_image_ctx, &on_finish, "snap"); | |
927 | ||
928 | C_SaferCond on_start_ready; | |
929 | C_SaferCond on_start_safe; | |
930 | when_process(mock_journal_replay, | |
931 | EventEntry{SnapRemoveEvent(123, | |
932 | cls::rbd::UserSnapshotNamespace(), | |
933 | "snap")}, | |
934 | &on_start_ready, | |
935 | &on_start_safe); | |
936 | ASSERT_EQ(0, on_start_ready.wait()); | |
937 | ||
938 | C_SaferCond on_finish_ready; | |
939 | C_SaferCond on_finish_safe; | |
940 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
941 | &on_finish_ready, &on_finish_safe); | |
942 | ||
943 | wait_for_op_invoked(&on_finish, -ENOENT); | |
944 | ASSERT_EQ(0, on_start_safe.wait()); | |
945 | ASSERT_EQ(0, on_finish_ready.wait()); | |
946 | ASSERT_EQ(0, on_finish_safe.wait()); | |
947 | } | |
948 | ||
949 | TEST_F(TestMockJournalReplay, SnapRenameEvent) { | |
950 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
951 | ||
952 | librbd::ImageCtx *ictx; | |
953 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
954 | ||
955 | MockReplayImageCtx mock_image_ctx(*ictx); | |
956 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
957 | expect_op_work_queue(mock_image_ctx); | |
958 | ||
959 | InSequence seq; | |
960 | Context *on_finish = nullptr; | |
961 | expect_refresh_image(mock_image_ctx, false, 0); | |
962 | expect_snap_rename(mock_image_ctx, &on_finish, 234, "snap"); | |
963 | ||
964 | C_SaferCond on_start_ready; | |
965 | C_SaferCond on_start_safe; | |
966 | when_process(mock_journal_replay, | |
967 | EventEntry{SnapRenameEvent(123, 234, "snap1", "snap")}, | |
968 | &on_start_ready, &on_start_safe); | |
969 | ASSERT_EQ(0, on_start_ready.wait()); | |
970 | ||
971 | C_SaferCond on_finish_ready; | |
972 | C_SaferCond on_finish_safe; | |
973 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
974 | &on_finish_ready, &on_finish_safe); | |
975 | ||
976 | wait_for_op_invoked(&on_finish, 0); | |
977 | ASSERT_EQ(0, on_start_safe.wait()); | |
978 | ASSERT_EQ(0, on_finish_ready.wait()); | |
979 | ASSERT_EQ(0, on_finish_safe.wait()); | |
980 | } | |
981 | ||
982 | TEST_F(TestMockJournalReplay, SnapRenameEventExists) { | |
983 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
984 | ||
985 | librbd::ImageCtx *ictx; | |
986 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
987 | ||
988 | MockReplayImageCtx mock_image_ctx(*ictx); | |
989 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
990 | expect_op_work_queue(mock_image_ctx); | |
991 | ||
992 | InSequence seq; | |
993 | Context *on_finish = nullptr; | |
994 | expect_refresh_image(mock_image_ctx, false, 0); | |
995 | expect_snap_rename(mock_image_ctx, &on_finish, 234, "snap"); | |
996 | ||
997 | C_SaferCond on_start_ready; | |
998 | C_SaferCond on_start_safe; | |
999 | when_process(mock_journal_replay, | |
1000 | EventEntry{SnapRenameEvent(123, 234, "snap1", "snap")}, | |
1001 | &on_start_ready, &on_start_safe); | |
1002 | ASSERT_EQ(0, on_start_ready.wait()); | |
1003 | ||
1004 | C_SaferCond on_finish_ready; | |
1005 | C_SaferCond on_finish_safe; | |
1006 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1007 | &on_finish_ready, &on_finish_safe); | |
1008 | ||
1009 | wait_for_op_invoked(&on_finish, -EEXIST); | |
1010 | ASSERT_EQ(0, on_start_safe.wait()); | |
1011 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1012 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1013 | } | |
1014 | ||
1015 | TEST_F(TestMockJournalReplay, SnapProtectEvent) { | |
1016 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1017 | ||
1018 | librbd::ImageCtx *ictx; | |
1019 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1020 | ||
1021 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1022 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1023 | expect_op_work_queue(mock_image_ctx); | |
1024 | ||
1025 | InSequence seq; | |
1026 | Context *on_finish = nullptr; | |
1027 | expect_refresh_image(mock_image_ctx, false, 0); | |
1028 | expect_snap_protect(mock_image_ctx, &on_finish, "snap"); | |
1029 | ||
1030 | C_SaferCond on_start_ready; | |
1031 | C_SaferCond on_start_safe; | |
1032 | when_process(mock_journal_replay, | |
1033 | EventEntry{SnapProtectEvent(123, | |
1034 | cls::rbd::UserSnapshotNamespace(), | |
1035 | "snap")}, | |
1036 | &on_start_ready, | |
1037 | &on_start_safe); | |
1038 | ASSERT_EQ(0, on_start_ready.wait()); | |
1039 | ||
1040 | C_SaferCond on_finish_ready; | |
1041 | C_SaferCond on_finish_safe; | |
1042 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1043 | &on_finish_ready, &on_finish_safe); | |
1044 | ||
1045 | wait_for_op_invoked(&on_finish, 0); | |
1046 | ASSERT_EQ(0, on_start_safe.wait()); | |
1047 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1048 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1049 | } | |
1050 | ||
1051 | TEST_F(TestMockJournalReplay, SnapProtectEventBusy) { | |
1052 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1053 | ||
1054 | librbd::ImageCtx *ictx; | |
1055 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1056 | ||
1057 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1058 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1059 | expect_op_work_queue(mock_image_ctx); | |
1060 | ||
1061 | InSequence seq; | |
1062 | Context *on_finish = nullptr; | |
1063 | expect_refresh_image(mock_image_ctx, false, 0); | |
1064 | expect_snap_protect(mock_image_ctx, &on_finish, "snap"); | |
1065 | ||
1066 | C_SaferCond on_start_ready; | |
1067 | C_SaferCond on_start_safe; | |
1068 | when_process(mock_journal_replay, | |
1069 | EventEntry{SnapProtectEvent(123, | |
1070 | cls::rbd::UserSnapshotNamespace(), | |
1071 | "snap")}, | |
1072 | &on_start_ready, | |
1073 | &on_start_safe); | |
1074 | ASSERT_EQ(0, on_start_ready.wait()); | |
1075 | ||
1076 | C_SaferCond on_finish_ready; | |
1077 | C_SaferCond on_finish_safe; | |
1078 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1079 | &on_finish_ready, &on_finish_safe); | |
1080 | ||
1081 | wait_for_op_invoked(&on_finish, -EBUSY); | |
1082 | ASSERT_EQ(0, on_start_safe.wait()); | |
1083 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1084 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1085 | } | |
1086 | ||
1087 | TEST_F(TestMockJournalReplay, SnapUnprotectEvent) { | |
1088 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1089 | ||
1090 | librbd::ImageCtx *ictx; | |
1091 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1092 | ||
1093 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1094 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1095 | expect_op_work_queue(mock_image_ctx); | |
1096 | ||
1097 | InSequence seq; | |
1098 | Context *on_finish = nullptr; | |
1099 | expect_refresh_image(mock_image_ctx, false, 0); | |
1100 | expect_snap_unprotect(mock_image_ctx, &on_finish, "snap"); | |
1101 | ||
1102 | C_SaferCond on_start_ready; | |
1103 | C_SaferCond on_start_safe; | |
1104 | when_process(mock_journal_replay, | |
1105 | EventEntry{SnapUnprotectEvent(123, | |
1106 | cls::rbd::UserSnapshotNamespace(), | |
1107 | "snap")}, | |
1108 | &on_start_ready, | |
1109 | &on_start_safe); | |
1110 | ASSERT_EQ(0, on_start_ready.wait()); | |
1111 | ||
1112 | C_SaferCond on_finish_ready; | |
1113 | C_SaferCond on_finish_safe; | |
1114 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1115 | &on_finish_ready, &on_finish_safe); | |
1116 | ||
1117 | wait_for_op_invoked(&on_finish, 0); | |
1118 | ASSERT_EQ(0, on_start_safe.wait()); | |
1119 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1120 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1121 | } | |
1122 | ||
1123 | TEST_F(TestMockJournalReplay, SnapUnprotectOpFinishBusy) { | |
1124 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1125 | ||
1126 | librbd::ImageCtx *ictx; | |
1127 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1128 | ||
1129 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1130 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1131 | expect_op_work_queue(mock_image_ctx); | |
1132 | ||
1133 | InSequence seq; | |
1134 | C_SaferCond on_start_ready; | |
1135 | C_SaferCond on_start_safe; | |
1136 | when_process(mock_journal_replay, | |
1137 | EventEntry{SnapUnprotectEvent(123, | |
1138 | cls::rbd::UserSnapshotNamespace(), | |
1139 | "snap")}, | |
1140 | &on_start_ready, | |
1141 | &on_start_safe); | |
1142 | ASSERT_EQ(0, on_start_ready.wait()); | |
1143 | ||
1144 | // aborts the snap unprotect op if image had children | |
1145 | C_SaferCond on_finish_ready; | |
1146 | C_SaferCond on_finish_safe; | |
1147 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, -EBUSY)}, | |
1148 | &on_finish_ready, &on_finish_safe); | |
1149 | ||
1150 | ASSERT_EQ(0, on_start_safe.wait()); | |
1151 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1152 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1153 | } | |
1154 | ||
1155 | TEST_F(TestMockJournalReplay, SnapUnprotectEventInvalid) { | |
1156 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1157 | ||
1158 | librbd::ImageCtx *ictx; | |
1159 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1160 | ||
1161 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1162 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1163 | expect_op_work_queue(mock_image_ctx); | |
1164 | ||
1165 | InSequence seq; | |
1166 | Context *on_finish = nullptr; | |
1167 | expect_refresh_image(mock_image_ctx, false, 0); | |
1168 | expect_snap_unprotect(mock_image_ctx, &on_finish, "snap"); | |
1169 | ||
1170 | C_SaferCond on_start_ready; | |
1171 | C_SaferCond on_start_safe; | |
1172 | when_process(mock_journal_replay, | |
1173 | EventEntry{SnapUnprotectEvent(123, | |
1174 | cls::rbd::UserSnapshotNamespace(), | |
1175 | "snap")}, | |
1176 | &on_start_ready, | |
1177 | &on_start_safe); | |
1178 | ASSERT_EQ(0, on_start_ready.wait()); | |
1179 | ||
1180 | C_SaferCond on_finish_ready; | |
1181 | C_SaferCond on_finish_safe; | |
1182 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1183 | &on_finish_ready, &on_finish_safe); | |
1184 | ||
1185 | wait_for_op_invoked(&on_finish, -EINVAL); | |
1186 | ASSERT_EQ(0, on_start_safe.wait()); | |
1187 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1188 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1189 | } | |
1190 | ||
1191 | TEST_F(TestMockJournalReplay, SnapRollbackEvent) { | |
1192 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1193 | ||
1194 | librbd::ImageCtx *ictx; | |
1195 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1196 | ||
1197 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1198 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1199 | expect_op_work_queue(mock_image_ctx); | |
1200 | ||
1201 | InSequence seq; | |
1202 | Context *on_finish = nullptr; | |
1203 | expect_refresh_image(mock_image_ctx, false, 0); | |
1204 | expect_snap_rollback(mock_image_ctx, &on_finish, "snap"); | |
1205 | ||
1206 | C_SaferCond on_start_ready; | |
1207 | C_SaferCond on_start_safe; | |
1208 | when_process(mock_journal_replay, | |
1209 | EventEntry{SnapRollbackEvent(123, | |
1210 | cls::rbd::UserSnapshotNamespace(), | |
1211 | "snap")}, | |
1212 | &on_start_ready, | |
1213 | &on_start_safe); | |
1214 | ASSERT_EQ(0, on_start_ready.wait()); | |
1215 | ||
1216 | C_SaferCond on_finish_ready; | |
1217 | C_SaferCond on_finish_safe; | |
1218 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1219 | &on_finish_ready, &on_finish_safe); | |
1220 | ||
1221 | wait_for_op_invoked(&on_finish, 0); | |
1222 | ASSERT_EQ(0, on_start_safe.wait()); | |
1223 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1224 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1225 | } | |
1226 | ||
1227 | TEST_F(TestMockJournalReplay, RenameEvent) { | |
1228 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1229 | ||
1230 | librbd::ImageCtx *ictx; | |
1231 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1232 | ||
1233 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1234 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1235 | expect_op_work_queue(mock_image_ctx); | |
1236 | ||
1237 | InSequence seq; | |
1238 | Context *on_finish = nullptr; | |
1239 | expect_refresh_image(mock_image_ctx, false, 0); | |
1240 | expect_rename(mock_image_ctx, &on_finish, "image"); | |
1241 | ||
1242 | C_SaferCond on_start_ready; | |
1243 | C_SaferCond on_start_safe; | |
1244 | when_process(mock_journal_replay, EventEntry{RenameEvent(123, "image")}, | |
1245 | &on_start_ready, &on_start_safe); | |
1246 | ASSERT_EQ(0, on_start_ready.wait()); | |
1247 | ||
1248 | C_SaferCond on_finish_ready; | |
1249 | C_SaferCond on_finish_safe; | |
1250 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1251 | &on_finish_ready, &on_finish_safe); | |
1252 | ||
1253 | wait_for_op_invoked(&on_finish, 0); | |
1254 | ASSERT_EQ(0, on_start_safe.wait()); | |
1255 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1256 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1257 | } | |
1258 | ||
1259 | TEST_F(TestMockJournalReplay, RenameEventExists) { | |
1260 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1261 | ||
1262 | librbd::ImageCtx *ictx; | |
1263 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1264 | ||
1265 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1266 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1267 | expect_op_work_queue(mock_image_ctx); | |
1268 | ||
1269 | InSequence seq; | |
1270 | Context *on_finish = nullptr; | |
1271 | expect_refresh_image(mock_image_ctx, false, 0); | |
1272 | expect_rename(mock_image_ctx, &on_finish, "image"); | |
1273 | ||
1274 | C_SaferCond on_start_ready; | |
1275 | C_SaferCond on_start_safe; | |
1276 | when_process(mock_journal_replay, EventEntry{RenameEvent(123, "image")}, | |
1277 | &on_start_ready, &on_start_safe); | |
1278 | ASSERT_EQ(0, on_start_ready.wait()); | |
1279 | ||
1280 | C_SaferCond on_finish_ready; | |
1281 | C_SaferCond on_finish_safe; | |
1282 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1283 | &on_finish_ready, &on_finish_safe); | |
1284 | ||
1285 | wait_for_op_invoked(&on_finish, -EEXIST); | |
1286 | ASSERT_EQ(0, on_start_safe.wait()); | |
1287 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1288 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1289 | } | |
1290 | ||
1291 | TEST_F(TestMockJournalReplay, ResizeEvent) { | |
1292 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1293 | ||
1294 | librbd::ImageCtx *ictx; | |
1295 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1296 | ||
1297 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1298 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1299 | expect_op_work_queue(mock_image_ctx); | |
1300 | ||
1301 | InSequence seq; | |
1302 | Context *on_finish = nullptr; | |
1303 | expect_refresh_image(mock_image_ctx, false, 0); | |
1304 | expect_resize(mock_image_ctx, &on_finish, 234, 123); | |
1305 | ||
1306 | C_SaferCond on_start_ready; | |
1307 | C_SaferCond on_start_safe; | |
1308 | when_process(mock_journal_replay, EventEntry{ResizeEvent(123, 234)}, | |
1309 | &on_start_ready, &on_start_safe); | |
1310 | ||
1311 | C_SaferCond on_resume; | |
1312 | when_replay_op_ready(mock_journal_replay, 123, &on_resume); | |
1313 | ASSERT_EQ(0, on_start_ready.wait()); | |
1314 | ||
1315 | C_SaferCond on_finish_ready; | |
1316 | C_SaferCond on_finish_safe; | |
1317 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1318 | &on_finish_ready, &on_finish_safe); | |
1319 | ||
1320 | ASSERT_EQ(0, on_resume.wait()); | |
1321 | wait_for_op_invoked(&on_finish, 0); | |
1322 | ||
1323 | ASSERT_EQ(0, on_start_safe.wait()); | |
1324 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1325 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1326 | } | |
1327 | ||
1328 | TEST_F(TestMockJournalReplay, FlattenEvent) { | |
1329 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1330 | ||
1331 | librbd::ImageCtx *ictx; | |
1332 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1333 | ||
1334 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1335 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1336 | expect_op_work_queue(mock_image_ctx); | |
1337 | ||
1338 | InSequence seq; | |
1339 | Context *on_finish = nullptr; | |
1340 | expect_refresh_image(mock_image_ctx, false, 0); | |
1341 | expect_flatten(mock_image_ctx, &on_finish); | |
1342 | ||
1343 | C_SaferCond on_start_ready; | |
1344 | C_SaferCond on_start_safe; | |
1345 | when_process(mock_journal_replay, EventEntry{FlattenEvent(123)}, | |
1346 | &on_start_ready, &on_start_safe); | |
1347 | ASSERT_EQ(0, on_start_ready.wait()); | |
1348 | ||
1349 | C_SaferCond on_finish_ready; | |
1350 | C_SaferCond on_finish_safe; | |
1351 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1352 | &on_finish_ready, &on_finish_safe); | |
1353 | ||
1354 | wait_for_op_invoked(&on_finish, 0); | |
1355 | ASSERT_EQ(0, on_start_safe.wait()); | |
1356 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1357 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1358 | } | |
1359 | ||
1360 | TEST_F(TestMockJournalReplay, FlattenEventInvalid) { | |
1361 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1362 | ||
1363 | librbd::ImageCtx *ictx; | |
1364 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1365 | ||
1366 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1367 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1368 | expect_op_work_queue(mock_image_ctx); | |
1369 | ||
1370 | InSequence seq; | |
1371 | Context *on_finish = nullptr; | |
1372 | expect_refresh_image(mock_image_ctx, false, 0); | |
1373 | expect_flatten(mock_image_ctx, &on_finish); | |
1374 | ||
1375 | C_SaferCond on_start_ready; | |
1376 | C_SaferCond on_start_safe; | |
1377 | when_process(mock_journal_replay, EventEntry{FlattenEvent(123)}, | |
1378 | &on_start_ready, &on_start_safe); | |
1379 | ASSERT_EQ(0, on_start_ready.wait()); | |
1380 | ||
1381 | C_SaferCond on_finish_ready; | |
1382 | C_SaferCond on_finish_safe; | |
1383 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1384 | &on_finish_ready, &on_finish_safe); | |
1385 | ||
1386 | wait_for_op_invoked(&on_finish, -EINVAL); | |
1387 | ASSERT_EQ(0, on_start_safe.wait()); | |
1388 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1389 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1390 | } | |
1391 | ||
1392 | TEST_F(TestMockJournalReplay, UpdateFeaturesEvent) { | |
1393 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1394 | ||
1395 | librbd::ImageCtx *ictx; | |
1396 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1397 | ||
1398 | uint64_t features = RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF; | |
1399 | bool enabled = !ictx->test_features(features); | |
1400 | ||
1401 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1402 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1403 | expect_op_work_queue(mock_image_ctx); | |
1404 | ||
1405 | InSequence seq; | |
1406 | Context *on_finish = nullptr; | |
1407 | expect_refresh_image(mock_image_ctx, false, 0); | |
1408 | expect_update_features(mock_image_ctx, &on_finish, features, enabled, 123); | |
1409 | ||
1410 | C_SaferCond on_start_ready; | |
1411 | C_SaferCond on_start_safe; | |
1412 | when_process(mock_journal_replay, | |
1413 | EventEntry{UpdateFeaturesEvent(123, features, enabled)}, | |
1414 | &on_start_ready, &on_start_safe); | |
1415 | ||
1416 | C_SaferCond on_resume; | |
1417 | when_replay_op_ready(mock_journal_replay, 123, &on_resume); | |
1418 | ASSERT_EQ(0, on_start_ready.wait()); | |
1419 | ||
1420 | C_SaferCond on_finish_ready; | |
1421 | C_SaferCond on_finish_safe; | |
1422 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1423 | &on_finish_ready, &on_finish_safe); | |
1424 | ||
1425 | ASSERT_EQ(0, on_resume.wait()); | |
1426 | wait_for_op_invoked(&on_finish, 0); | |
1427 | ||
1428 | ASSERT_EQ(0, on_start_safe.wait()); | |
1429 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1430 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1431 | } | |
1432 | ||
1433 | TEST_F(TestMockJournalReplay, MetadataSetEvent) { | |
1434 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1435 | ||
1436 | librbd::ImageCtx *ictx; | |
1437 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1438 | ||
1439 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1440 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1441 | expect_op_work_queue(mock_image_ctx); | |
1442 | ||
1443 | InSequence seq; | |
1444 | Context *on_finish = nullptr; | |
1445 | expect_refresh_image(mock_image_ctx, false, 0); | |
1446 | expect_metadata_set(mock_image_ctx, &on_finish, "key", "value"); | |
1447 | ||
1448 | C_SaferCond on_start_ready; | |
1449 | C_SaferCond on_start_safe; | |
1450 | when_process(mock_journal_replay, EventEntry{MetadataSetEvent(123, "key", "value")}, | |
1451 | &on_start_ready, &on_start_safe); | |
1452 | ASSERT_EQ(0, on_start_ready.wait()); | |
1453 | ||
1454 | C_SaferCond on_finish_ready; | |
1455 | C_SaferCond on_finish_safe; | |
1456 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1457 | &on_finish_ready, &on_finish_safe); | |
1458 | ||
1459 | wait_for_op_invoked(&on_finish, 0); | |
1460 | ASSERT_EQ(0, on_start_safe.wait()); | |
1461 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1462 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1463 | } | |
1464 | ||
1465 | TEST_F(TestMockJournalReplay, MetadataRemoveEvent) { | |
1466 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1467 | ||
1468 | librbd::ImageCtx *ictx; | |
1469 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1470 | ||
1471 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1472 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1473 | expect_op_work_queue(mock_image_ctx); | |
1474 | ||
1475 | InSequence seq; | |
1476 | Context *on_finish = nullptr; | |
1477 | expect_refresh_image(mock_image_ctx, false, 0); | |
1478 | expect_metadata_remove(mock_image_ctx, &on_finish, "key"); | |
1479 | ||
1480 | C_SaferCond on_start_ready; | |
1481 | C_SaferCond on_start_safe; | |
1482 | when_process(mock_journal_replay, EventEntry{MetadataRemoveEvent(123, "key")}, | |
1483 | &on_start_ready, &on_start_safe); | |
1484 | ASSERT_EQ(0, on_start_ready.wait()); | |
1485 | ||
1486 | C_SaferCond on_finish_ready; | |
1487 | C_SaferCond on_finish_safe; | |
1488 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1489 | &on_finish_ready, &on_finish_safe); | |
1490 | ||
1491 | wait_for_op_invoked(&on_finish, 0); | |
1492 | ASSERT_EQ(0, on_start_safe.wait()); | |
1493 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1494 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1495 | } | |
1496 | ||
1497 | TEST_F(TestMockJournalReplay, MetadataRemoveEventDNE) { | |
1498 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1499 | ||
1500 | librbd::ImageCtx *ictx; | |
1501 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1502 | ||
1503 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1504 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1505 | expect_op_work_queue(mock_image_ctx); | |
1506 | ||
1507 | InSequence seq; | |
1508 | Context *on_finish = nullptr; | |
1509 | expect_refresh_image(mock_image_ctx, false, 0); | |
1510 | expect_metadata_remove(mock_image_ctx, &on_finish, "key"); | |
1511 | ||
1512 | C_SaferCond on_start_ready; | |
1513 | C_SaferCond on_start_safe; | |
1514 | when_process(mock_journal_replay, EventEntry{MetadataRemoveEvent(123, "key")}, | |
1515 | &on_start_ready, &on_start_safe); | |
1516 | ASSERT_EQ(0, on_start_ready.wait()); | |
1517 | ||
1518 | C_SaferCond on_finish_ready; | |
1519 | C_SaferCond on_finish_safe; | |
1520 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1521 | &on_finish_ready, &on_finish_safe); | |
1522 | ||
1523 | wait_for_op_invoked(&on_finish, -ENOENT); | |
1524 | ASSERT_EQ(0, on_start_safe.wait()); | |
1525 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1526 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1527 | } | |
1528 | ||
1529 | TEST_F(TestMockJournalReplay, UnknownEvent) { | |
1530 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1531 | ||
1532 | librbd::ImageCtx *ictx; | |
1533 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1534 | ||
1535 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1536 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1537 | expect_op_work_queue(mock_image_ctx); | |
1538 | ||
1539 | InSequence seq; | |
1540 | ||
1541 | bufferlist bl; | |
1542 | ENCODE_START(1, 1, bl); | |
1543 | ::encode(static_cast<uint32_t>(-1), bl); | |
1544 | ENCODE_FINISH(bl); | |
1545 | ||
1546 | bufferlist::iterator it = bl.begin(); | |
1547 | C_SaferCond on_ready; | |
1548 | C_SaferCond on_safe; | |
1549 | when_process(mock_journal_replay, &it, &on_ready, &on_safe); | |
1550 | ||
1551 | ASSERT_EQ(0, on_safe.wait()); | |
1552 | ASSERT_EQ(0, on_ready.wait()); | |
1553 | } | |
1554 | ||
1555 | TEST_F(TestMockJournalReplay, RefreshImageBeforeOpStart) { | |
1556 | REQUIRE_FEATURE(RBD_FEATURE_JOURNALING); | |
1557 | ||
1558 | librbd::ImageCtx *ictx; | |
1559 | ASSERT_EQ(0, open_image(m_image_name, &ictx)); | |
1560 | ||
1561 | MockReplayImageCtx mock_image_ctx(*ictx); | |
1562 | MockJournalReplay mock_journal_replay(mock_image_ctx); | |
1563 | expect_op_work_queue(mock_image_ctx); | |
1564 | ||
1565 | InSequence seq; | |
1566 | Context *on_finish = nullptr; | |
1567 | expect_refresh_image(mock_image_ctx, true, 0); | |
1568 | expect_resize(mock_image_ctx, &on_finish, 234, 123); | |
1569 | ||
1570 | C_SaferCond on_start_ready; | |
1571 | C_SaferCond on_start_safe; | |
1572 | when_process(mock_journal_replay, EventEntry{ResizeEvent(123, 234)}, | |
1573 | &on_start_ready, &on_start_safe); | |
1574 | ||
1575 | C_SaferCond on_resume; | |
1576 | when_replay_op_ready(mock_journal_replay, 123, &on_resume); | |
1577 | ASSERT_EQ(0, on_start_ready.wait()); | |
1578 | ||
1579 | C_SaferCond on_finish_ready; | |
1580 | C_SaferCond on_finish_safe; | |
1581 | when_process(mock_journal_replay, EventEntry{OpFinishEvent(123, 0)}, | |
1582 | &on_finish_ready, &on_finish_safe); | |
1583 | ||
1584 | ASSERT_EQ(0, on_resume.wait()); | |
1585 | wait_for_op_invoked(&on_finish, 0); | |
1586 | ||
1587 | ASSERT_EQ(0, on_start_safe.wait()); | |
1588 | ASSERT_EQ(0, on_finish_ready.wait()); | |
1589 | ASSERT_EQ(0, on_finish_safe.wait()); | |
1590 | } | |
1591 | ||
1592 | } // namespace journal | |
1593 | } // namespace librbd |