int snap_set(ImageCtx *ictx, const char *snap_name);
+ int list_images_v2(librados::IoCtx& io_ctx,
+ std::map<std::string, std::string>& images);
int list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
int list_children(ImageCtx *ictx,
std::set<std::pair<std::string, std::string> > & names);
{
Mutex::Locker locker(m_lock);
m_bootstrap_request = nullptr;
+ if (m_local_image_ctx) {
+ m_local_image_id = m_local_image_ctx->id;
+ m_local_image_name = m_local_image_ctx->name;
+ }
}
if (r == -EREMOTEIO) {
std::string get_name() { Mutex::Locker l(m_lock); return m_name; };
void set_state_description(int r, const std::string &desc);
+ inline uint64_t get_local_pool_id() { return m_local_pool_id; }
+ inline const std::string get_local_image_id() { return m_local_image_id; }
+ inline const std::string get_global_image_id() { return m_global_image_id; }
+ inline const std::string get_local_image_name() { return m_local_image_name; }
void start(Context *on_finish = nullptr,
const BootstrapParams *bootstrap_params = nullptr,
const peer_t &peer = kv.first;
if (m_replayers.find(peer) == m_replayers.end()) {
dout(20) << "starting replayer for " << peer << dendl;
- unique_ptr<Replayer> replayer(new Replayer(m_threads, m_local, peer,
- m_args));
+ unique_ptr<Replayer> replayer(new Replayer(m_threads, m_image_deleter,
+ m_local, peer, m_args));
// TODO: make async, and retry connecting within replayer
int r = replayer->init();
if (r < 0) {
continue;
}
+ std::map<std::string, std::string> images_map;
+ r = librbd::list_images_v2(ioctx, images_map);
+ if (r < 0) {
+ derr << "error retrieving image names from pool " << pool_name << ": "
+ << cpp_strerror(r) << dendl;
+ }
+
+ std::map<std::string, std::string> image_id_to_name;
+ for (const auto& img_pair : images_map) {
+ image_id_to_name.insert(std::make_pair(img_pair.second, img_pair.first));
+ }
+
std::set<ImageIds> image_ids;
std::string last_read = "";
int max_read = 1024;
continue;
}
for (auto it = mirror_images.begin(); it != mirror_images.end(); ++it) {
- image_ids.insert(ImageIds(it->first, it->second));
+ boost::optional<std::string> image_name(boost::none);
+ auto it2 = image_id_to_name.find(it->first);
+ if (it2 != image_id_to_name.end()) {
+ image_name = it2->second;
+ }
+ image_ids.insert(ImageIds(it->first, image_name, it->second));
}
if (!mirror_images.empty()) {
last_read = mirror_images.rbegin()->first;
public:
struct ImageIds {
std::string id;
+ boost::optional<std::string> name;
std::string global_id;
- ImageIds(const std::string &id, const std::string &global_id = "")
- : id(id), global_id(global_id) {
+ ImageIds(const std::string &id,
+ const boost::optional<std::string> &name = boost::none,
+ const std::string &global_id = "")
+ : id(id), name(name), global_id(global_id) {
}
inline bool operator==(const ImageIds &rhs) const {
- return (id == rhs.id && global_id == rhs.global_id);
+ return (id == rhs.id && name == rhs.name && global_id == rhs.global_id);
}
inline bool operator<(const ImageIds &rhs) const {
return id < rhs.id;
{
dout(20) << "replaying for " << m_peer << dendl;
+ m_image_deleter.reset(new ImageDeleter(m_peer.cluster_name, m_local));
+
// NOTE: manually bootstrap a CephContext here instead of via
// the librados API to avoid mixing global singletons between
// the librados shared library and the daemon
}
// Stopping
+ m_image_deleter.reset();
+
PoolImageIds empty_sources;
while (true) {
Mutex::Locker l(m_lock);
}
}
+ if (f) {
+ f->close_section();
+ f->open_object_section("image_deleter");
+ }
+
+ m_image_deleter->print_status(f, ss);
+
if (f) {
f->close_section();
f->close_section();
dout(20) << "starting image replayer for "
<< it->second->get_global_image_id() << dendl;
}
- start_image_replayer(it->second);
+ start_image_replayer(it->second, image_id.name);
}
}
}
m_status_watchers.erase(watcher_it);
}
-void Replayer::start_image_replayer(unique_ptr<ImageReplayer<> > &image_replayer)
+void Replayer::start_image_replayer(unique_ptr<ImageReplayer<> > &image_replayer,
+ const boost::optional<std::string>& image_name)
{
if (!image_replayer->is_stopped()) {
return;
}
- image_replayer->start();
+ if (image_name) {
+ FunctionContext *ctx = new FunctionContext(
+ [&] (int r) {
+ if (r >= 0) {
+ image_replayer->start();
+ } else {
+ start_image_replayer(image_replayer, image_name);
+ }
+ }
+ );
+ m_image_deleter->wait_for_scheduled_deletion(image_name.get(), ctx, false);
+ }
}
bool Replayer::stop_image_replayer(unique_ptr<ImageReplayer<> > &image_replayer)
}
if (image_replayer->is_running()) {
- image_replayer->stop();
+ FunctionContext *ctx = new FunctionContext(
+ [&image_replayer, this] (int r) {
+ if (m_image_deleter) {
+ m_image_deleter->schedule_image_delete(
+ image_replayer->get_local_pool_id(),
+ image_replayer->get_local_image_id(),
+ image_replayer->get_local_image_name(),
+ image_replayer->get_global_image_id());
+ }
+ }
+ );
+ image_replayer->stop(ctx);
} else {
// TODO: check how long it is stopping and alert if it is too long.
}
#include "ClusterWatcher.h"
#include "ImageReplayer.h"
#include "PoolWatcher.h"
+#include "ImageDeleter.h"
#include "types.h"
namespace rbd {
void set_sources(const PoolImageIds &pool_image_ids);
- void start_image_replayer(unique_ptr<ImageReplayer<> > &image_replayer);
+ void start_image_replayer(unique_ptr<ImageReplayer<> > &image_replayer,
+ const boost::optional<std::string>& image_name);
bool stop_image_replayer(unique_ptr<ImageReplayer<> > &image_replayer);
int mirror_image_status_init(int64_t pool_id, librados::IoCtx& ioctx);
std::unique_ptr<ImageReplayer<> > > > m_images;
std::map<int64_t, std::unique_ptr<MirrorStatusWatchCtx> > m_status_watchers;
ReplayerAdminSocketHook *m_asok_hook;
+ std::unique_ptr<ImageDeleter> m_image_deleter;
class ReplayerThread : public Thread {
Replayer *m_replayer;