]> git.proxmox.com Git - ceph.git/blame - ceph/src/rbd_replay/actions.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / rbd_replay / actions.cc
CommitLineData
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 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2014 Adam Crume <adamcrume@gmail.com>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include "actions.hpp"
16#include <boost/foreach.hpp>
17#include <cstdlib>
18#include "PendingIO.hpp"
19#include "rbd_replay_debug.hpp"
20
21#define dout_context g_ceph_context
22
23using namespace rbd_replay;
7c673cae
FG
24
25namespace {
26
27std::string create_fake_data() {
28 char data[1 << 20]; // 1 MB
29 for (unsigned int i = 0; i < sizeof(data); i++) {
30 data[i] = (char) i;
31 }
32 return std::string(data, sizeof(data));
33}
34
35struct ConstructVisitor : public boost::static_visitor<Action::ptr> {
36 inline Action::ptr operator()(const action::StartThreadAction &action) const {
37 return Action::ptr(new StartThreadAction(action));
38 }
39
40 inline Action::ptr operator()(const action::StopThreadAction &action) const{
41 return Action::ptr(new StopThreadAction(action));
42 }
43
44 inline Action::ptr operator()(const action::ReadAction &action) const {
45 return Action::ptr(new ReadAction(action));
46 }
47
48 inline Action::ptr operator()(const action::AioReadAction &action) const {
49 return Action::ptr(new AioReadAction(action));
50 }
51
52 inline Action::ptr operator()(const action::WriteAction &action) const {
53 return Action::ptr(new WriteAction(action));
54 }
55
56 inline Action::ptr operator()(const action::AioWriteAction &action) const {
57 return Action::ptr(new AioWriteAction(action));
58 }
59
60 inline Action::ptr operator()(const action::DiscardAction &action) const {
61 return Action::ptr(new DiscardAction(action));
62 }
63
64 inline Action::ptr operator()(const action::AioDiscardAction &action) const {
65 return Action::ptr(new AioDiscardAction(action));
66 }
67
68 inline Action::ptr operator()(const action::OpenImageAction &action) const {
69 return Action::ptr(new OpenImageAction(action));
70 }
71
72 inline Action::ptr operator()(const action::CloseImageAction &action) const {
73 return Action::ptr(new CloseImageAction(action));
74 }
75
76 inline Action::ptr operator()(const action::AioOpenImageAction &action) const {
77 return Action::ptr(new AioOpenImageAction(action));
78 }
79
80 inline Action::ptr operator()(const action::AioCloseImageAction &action) const {
81 return Action::ptr(new AioCloseImageAction(action));
82 }
83
84 inline Action::ptr operator()(const action::UnknownAction &action) const {
85 return Action::ptr();
86 }
87};
88
89} // anonymous namespace
90
91std::ostream& rbd_replay::operator<<(std::ostream& o, const Action& a) {
92 return a.dump(o);
93}
94
95Action::ptr Action::construct(const action::ActionEntry &action_entry) {
96 return boost::apply_visitor(ConstructVisitor(), action_entry.action);
97}
98
99void StartThreadAction::perform(ActionCtx &ctx) {
100 cerr << "StartThreadAction should never actually be performed" << std::endl;
101 exit(1);
102}
103
104void StopThreadAction::perform(ActionCtx &ctx) {
105 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
106 ctx.stop();
107}
108
109void AioReadAction::perform(ActionCtx &worker) {
110 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
111 librbd::Image *image = worker.get_image(m_action.imagectx_id);
11fdf7f2 112 ceph_assert(image);
7c673cae
FG
113 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
114 worker.add_pending(io);
115 int r = image->aio_read(m_action.offset, m_action.length, io->bufferlist(), &io->completion());
116 assertf(r >= 0, "id = %d, r = %d", id(), r);
117}
118
119void ReadAction::perform(ActionCtx &worker) {
120 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
121 librbd::Image *image = worker.get_image(m_action.imagectx_id);
122 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
123 worker.add_pending(io);
124 ssize_t r = image->read(m_action.offset, m_action.length, io->bufferlist());
125 assertf(r >= 0, "id = %d, r = %d", id(), r);
126 worker.remove_pending(io);
127}
128
129void AioWriteAction::perform(ActionCtx &worker) {
130 static const std::string fake_data(create_fake_data());
131 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
132 librbd::Image *image = worker.get_image(m_action.imagectx_id);
133 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
134 uint64_t remaining = m_action.length;
135 while (remaining > 0) {
136 uint64_t n = std::min(remaining, (uint64_t)fake_data.length());
137 io->bufferlist().append(fake_data.data(), n);
138 remaining -= n;
139 }
140 worker.add_pending(io);
141 if (worker.readonly()) {
142 worker.remove_pending(io);
143 } else {
144 int r = image->aio_write(m_action.offset, m_action.length, io->bufferlist(), &io->completion());
145 assertf(r >= 0, "id = %d, r = %d", id(), r);
146 }
147}
148
149void WriteAction::perform(ActionCtx &worker) {
150 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
151 librbd::Image *image = worker.get_image(m_action.imagectx_id);
152 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
153 worker.add_pending(io);
154 io->bufferlist().append_zero(m_action.length);
155 if (!worker.readonly()) {
156 ssize_t r = image->write(m_action.offset, m_action.length, io->bufferlist());
157 assertf(r >= 0, "id = %d, r = %d", id(), r);
158 }
159 worker.remove_pending(io);
160}
161
162void AioDiscardAction::perform(ActionCtx &worker) {
163 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
164 librbd::Image *image = worker.get_image(m_action.imagectx_id);
165 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
166 worker.add_pending(io);
167 if (worker.readonly()) {
168 worker.remove_pending(io);
169 } else {
170 int r = image->aio_discard(m_action.offset, m_action.length, &io->completion());
171 assertf(r >= 0, "id = %d, r = %d", id(), r);
172 }
173}
174
175void DiscardAction::perform(ActionCtx &worker) {
176 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
177 librbd::Image *image = worker.get_image(m_action.imagectx_id);
178 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
179 worker.add_pending(io);
180 if (!worker.readonly()) {
181 ssize_t r = image->discard(m_action.offset, m_action.length);
182 assertf(r >= 0, "id = %d, r = %d", id(), r);
183 }
184 worker.remove_pending(io);
185}
186
187void OpenImageAction::perform(ActionCtx &worker) {
188 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
189 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
190 worker.add_pending(io);
191 librbd::Image *image = new librbd::Image();
192 librbd::RBD *rbd = worker.rbd();
193 rbd_loc name(worker.map_image_name(m_action.name, m_action.snap_name));
194 int r;
195 if (m_action.read_only || worker.readonly()) {
196 r = rbd->open_read_only(*worker.ioctx(), *image, name.image.c_str(), name.snap.c_str());
197 } else {
198 r = rbd->open(*worker.ioctx(), *image, name.image.c_str(), name.snap.c_str());
199 }
200 if (r) {
201 cerr << "Unable to open image '" << m_action.name
202 << "' with snap '" << m_action.snap_name
203 << "' (mapped to '" << name.str()
204 << "') and readonly " << m_action.read_only
205 << ": (" << -r << ") " << strerror(-r) << std::endl;
206 exit(1);
207 }
208 worker.put_image(m_action.imagectx_id, image);
209 worker.remove_pending(io);
210}
211
212void CloseImageAction::perform(ActionCtx &worker) {
213 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
214 worker.erase_image(m_action.imagectx_id);
215 worker.set_action_complete(pending_io_id());
216}
217
218void AioOpenImageAction::perform(ActionCtx &worker) {
219 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
220 // TODO: Make it async
221 PendingIO::ptr io(new PendingIO(pending_io_id(), worker));
222 worker.add_pending(io);
223 librbd::Image *image = new librbd::Image();
224 librbd::RBD *rbd = worker.rbd();
225 rbd_loc name(worker.map_image_name(m_action.name, m_action.snap_name));
226 int r;
227 if (m_action.read_only || worker.readonly()) {
228 r = rbd->open_read_only(*worker.ioctx(), *image, name.image.c_str(), name.snap.c_str());
229 } else {
230 r = rbd->open(*worker.ioctx(), *image, name.image.c_str(), name.snap.c_str());
231 }
232 if (r) {
233 cerr << "Unable to open image '" << m_action.name
234 << "' with snap '" << m_action.snap_name
235 << "' (mapped to '" << name.str()
236 << "') and readonly " << m_action.read_only
237 << ": (" << -r << ") " << strerror(-r) << std::endl;
238 exit(1);
239 }
240 worker.put_image(m_action.imagectx_id, image);
241 worker.remove_pending(io);
242}
243
244void AioCloseImageAction::perform(ActionCtx &worker) {
245 dout(ACTION_LEVEL) << "Performing " << *this << dendl;
246 // TODO: Make it async
247 worker.erase_image(m_action.imagectx_id);
248 worker.set_action_complete(pending_io_id());
249}