librbd::mirror_mode_set(m_local_io_ctx, RBD_MIRROR_MODE_IMAGE);
- m_deleter = new rbd::mirror::ImageDeleter(_rados,
- m_threads->work_queue, m_threads->timer, &m_threads->timer_lock);
+ m_deleter = new rbd::mirror::ImageDeleter(m_threads->work_queue,
+ m_threads->timer,
+ &m_threads->timer_lock);
EXPECT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, 1 << 20));
ImageCtx *ictx = new ImageCtx(m_image_name, "", "", m_local_io_ctx,
TEST_F(TestImageDeleter, Delete_NonPrimary_Image) {
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
TEST_F(TestImageDeleter, Fail_Delete_Primary_Image) {
promote_image();
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
// This test case represents a case that should never happen, unless
// there is bug in the implementation
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, "diff global id");
C_SaferCond ctx;
TEST_F(TestImageDeleter, Delete_Image_With_Child) {
create_snapshot();
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
create_snapshot("snap1");
create_snapshot("snap2");
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
TEST_F(TestImageDeleter, Delete_Image_With_ProtectedChild) {
create_snapshot("snap1", true);
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
create_snapshot("snap1", true);
create_snapshot("snap2", true);
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
TEST_F(TestImageDeleter, Delete_Image_With_Clone) {
std::string clone_id = create_clone();
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
ASSERT_EQ(1u, m_deleter->get_delete_queue_items().size());
ASSERT_EQ(0u, m_deleter->get_failed_queue_items().size());
- m_deleter->schedule_image_delete(m_local_pool_id, clone_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, clone_id,
"clone1", GLOBAL_CLONE_IMAGE_ID);
C_SaferCond ctx2;
EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx, m_local_image_id,
mirror_image));
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
EXPECT_EQ(0, cls_client::mirror_image_set(&m_local_io_ctx, m_local_image_id,
mirror_image));
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
TEST_F(TestImageDeleter, Delete_NonExistent_Image_Without_MirroringState) {
remove_image();
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
false);
EXPECT_EQ(0, ictx->state->open());
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
m_deleter->set_failed_timer_interval(2);
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
false);
EXPECT_EQ(0, ictx->state->open());
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
C_SaferCond ctx;
ASSERT_EQ(0u, m_deleter->get_delete_queue_items().size());
ASSERT_EQ(1u, m_deleter->get_failed_queue_items().size());
- m_deleter->schedule_image_delete(m_local_pool_id, m_local_image_id,
+ m_deleter->schedule_image_delete(_rados, m_local_pool_id, m_local_image_id,
m_image_name, GLOBAL_IMAGE_ID);
ASSERT_EQ(0u, m_deleter->get_delete_queue_items().size());
m_threads = new rbd::mirror::Threads(reinterpret_cast<CephContext*>(
m_local_ioctx.cct()));
- m_image_deleter.reset(new rbd::mirror::ImageDeleter(m_local_cluster,
- m_threads->work_queue,
+ m_image_deleter.reset(new rbd::mirror::ImageDeleter(m_threads->work_queue,
m_threads->timer,
&m_threads->timer_lock));
m_image_sync_throttler.reset(new rbd::mirror::ImageSyncThrottler<>());
#include "common/debug.h"
#include "common/errno.h"
#include "common/WorkQueue.h"
+#include "global/global_context.h"
#include "librbd/internal.h"
#include "librbd/ImageCtx.h"
#include "librbd/ImageState.h"
Commands commands;
};
-ImageDeleter::ImageDeleter(RadosRef local_cluster, ContextWQ *work_queue,
- SafeTimer *timer, Mutex *timer_lock)
- : m_local(local_cluster),
- m_running(1),
+ImageDeleter::ImageDeleter(ContextWQ *work_queue, SafeTimer *timer,
+ Mutex *timer_lock)
+ : m_running(1),
m_work_queue(work_queue),
m_delete_lock("rbd::mirror::ImageDeleter::Delete"),
m_image_deleter_thread(this),
m_failed_timer(timer),
m_failed_timer_lock(timer_lock),
- m_asok_hook(new ImageDeleterAdminSocketHook((CephContext *)local_cluster->cct(),
- this))
+ m_asok_hook(new ImageDeleterAdminSocketHook(g_ceph_context, this))
{
m_image_deleter_thread.create("image_deleter");
}
}
}
- curr_deletion = std::move(m_delete_queue.back());
+ m_active_delete = std::move(m_delete_queue.back());
m_delete_queue.pop_back();
m_delete_lock.Unlock();
}
}
-void ImageDeleter::schedule_image_delete(uint64_t local_pool_id,
+void ImageDeleter::schedule_image_delete(RadosRef local_rados,
+ uint64_t local_pool_id,
const std::string& local_image_id,
const std::string& local_image_name,
const std::string& global_image_id) {
}
m_delete_queue.push_front(unique_ptr<DeleteInfo>(
- new DeleteInfo(local_pool_id, local_image_id, local_image_name,
- global_image_id)));
+ new DeleteInfo(local_rados, local_pool_id, local_image_id,
+ local_image_name, global_image_id)));
m_delete_queue_cond.Signal();
}
bool ImageDeleter::process_image_delete() {
stringstream ss;
- curr_deletion->to_string(ss);
+ m_active_delete->to_string(ss);
std::string del_info_str = ss.str();
dout(10) << "start processing delete request: " << del_info_str << dendl;
int r;
// remote image was disabled, now we need to delete local image
IoCtx ioctx;
- r = m_local->ioctx_create2(curr_deletion->local_pool_id, ioctx);
+ r = m_active_delete->local_rados->ioctx_create2(
+ m_active_delete->local_pool_id, ioctx);
if (r < 0) {
derr << "error accessing local pool: " << cpp_strerror(r) << dendl;
enqueue_failed_delete(r);
dout(20) << "connected to local pool: " << ioctx.get_pool_name() << dendl;
bool is_primary = false;
- r = Journal<>::is_tag_owner(ioctx, curr_deletion->local_image_id, &is_primary);
+ r = Journal<>::is_tag_owner(ioctx, m_active_delete->local_image_id,
+ &is_primary);
if (r < 0 && r != -ENOENT) {
derr << "error retrieving image primary info: " << cpp_strerror(r)
<< dendl;
if (is_primary) {
dout(10) << "local image is the primary image, aborting deletion..."
<< dendl;
- m_delete_lock.Lock();
- DeleteInfo *del_info = curr_deletion.release();
- m_delete_lock.Unlock();
- del_info->notify(-EISPRM);
+ complete_active_delete(-EISPRM);
return true;
}
dout(20) << "local image is not the primary" << dendl;
bool has_snapshots;
- r = image_has_snapshots_and_children(&ioctx, curr_deletion->local_image_id,
+ r = image_has_snapshots_and_children(&ioctx, m_active_delete->local_image_id,
&has_snapshots);
if (r < 0) {
enqueue_failed_delete(r);
return true;
}
- mirror_image.global_image_id = curr_deletion->global_image_id;
+ mirror_image.global_image_id = m_active_delete->global_image_id;
mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
- r = cls_client::mirror_image_set(&ioctx, curr_deletion->local_image_id,
- mirror_image);
+ r = cls_client::mirror_image_set(&ioctx, m_active_delete->local_image_id,
+ mirror_image);
if (r == -ENOENT) {
dout(10) << "local image is not mirrored, aborting deletion..." << dendl;
- m_delete_lock.Lock();
- DeleteInfo *del_info = curr_deletion.release();
- m_delete_lock.Unlock();
- del_info->notify(r);
+ complete_active_delete(r);
return true;
} else if (r == -EEXIST || r == -EINVAL) {
- derr << "cannot disable mirroring for image id" << curr_deletion->local_image_id
+ derr << "cannot disable mirroring for image id "
+ << m_active_delete->local_image_id
<< ": global_image_id has changed/reused, aborting deletion: "
<< cpp_strerror(r) << dendl;
- m_delete_lock.Lock();
- DeleteInfo *del_info = curr_deletion.release();
- m_delete_lock.Unlock();
- del_info->notify(r);
+ complete_active_delete(r);
return true;
} else if (r < 0) {
derr << "cannot disable mirroring for image id "
- << curr_deletion->local_image_id << ": " << cpp_strerror(r) << dendl;
+ << m_active_delete->local_image_id << ": " << cpp_strerror(r) << dendl;
enqueue_failed_delete(r);
return true;
}
if (has_snapshots) {
dout(20) << "local image has snapshots" << dendl;
- ImageCtx *imgctx = new ImageCtx("", curr_deletion->local_image_id, nullptr,
- ioctx, false);
+ ImageCtx *imgctx = new ImageCtx("", m_active_delete->local_image_id,
+ nullptr, ioctx, false);
r = imgctx->state->open();
if (r < 0) {
- derr << "error opening image id " << curr_deletion->local_image_id
- << cpp_strerror(r) << dendl;
+ derr << "error opening image id " << m_active_delete->local_image_id
+ << ": " << cpp_strerror(r) << dendl;
enqueue_failed_delete(r);
delete imgctx;
return true;
if (r == -EBUSY) {
// there are still clones of snapshots of this image, therefore send
// the delete request to the end of the queue
- dout(10) << "local image id " << curr_deletion->local_image_id << " has "
+ dout(10) << "local image id " << m_active_delete->local_image_id << " has "
<< "snapshots with cloned children, postponing deletion..."
<< dendl;
imgctx->state->close();
Mutex::Locker l(m_delete_lock);
- curr_deletion->notify(r);
- m_delete_queue.push_front(std::move(curr_deletion));
+ m_active_delete->notify(r);
+ m_delete_queue.push_front(std::move(m_active_delete));
return false;
} else if (r < 0) {
derr << "error unprotecting snapshot " << imgctx->name << "@"
}
librbd::NoOpProgressContext ctx;
- r = librbd::remove(ioctx, curr_deletion->local_image_name.c_str(), ctx, true);
+ r = librbd::remove(ioctx, m_active_delete->local_image_name.c_str(), ctx,
+ true);
if (r < 0 && r != -ENOENT) {
- derr << "error removing image " << curr_deletion->local_image_name
+ derr << "error removing image " << m_active_delete->local_image_name
<< " from local pool: " << cpp_strerror(r) << dendl;
enqueue_failed_delete(r);
return true;
<< dendl;
}
- r = cls_client::mirror_image_remove(&ioctx, curr_deletion->local_image_id);
+ r = cls_client::mirror_image_remove(&ioctx, m_active_delete->local_image_id);
if (r < 0 && r != -ENOENT) {
derr << "error removing image from mirroring directory: "
<< cpp_strerror(r) << dendl;
return true;
}
- dout(10) << "Successfully deleted image: " << curr_deletion->local_image_name
- << dendl;
-
- m_delete_lock.Lock();
- DeleteInfo *del_info = curr_deletion.release();
- m_delete_lock.Unlock();
- del_info->notify(0);
+ dout(10) << "Successfully deleted image: "
+ << m_active_delete->local_image_name << dendl;
+ complete_active_delete(0);
return true;
}
return 0;
}
+void ImageDeleter::complete_active_delete(int r) {
+ dout(20) << dendl;
+
+ m_delete_lock.Lock();
+ DeleteInfo *del_info = m_active_delete.release();
+ assert(del_info != nullptr);
+ m_delete_lock.Unlock();
+ del_info->notify(r);
+}
+
void ImageDeleter::enqueue_failed_delete(int error_code) {
dout(20) << "enter" << dendl;
+ if (error_code == -EBLACKLISTED) {
+ derr << "blacklisted while deleting local image" << dendl;
+ complete_active_delete(error_code);
+ return;
+ }
+
m_delete_lock.Lock();
- if (curr_deletion->notify_on_failed_retry) {
- curr_deletion->notify(error_code);
+ if (m_active_delete->notify_on_failed_retry) {
+ m_active_delete->notify(error_code);
}
- curr_deletion->error_code = error_code;
+ m_active_delete->error_code = error_code;
bool was_empty = m_failed_queue.empty();
- m_failed_queue.push_front(std::move(curr_deletion));
+ m_failed_queue.push_front(std::move(m_active_delete));
m_delete_lock.Unlock();
if (was_empty) {
FunctionContext *ctx = new FunctionContext(
}
}
+unique_ptr<ImageDeleter::DeleteInfo> const* ImageDeleter::find_delete_info(
+ const std::string& image_name) {
+ assert(m_delete_lock.is_locked());
+
+ if (m_active_delete && m_active_delete->match(image_name)) {
+ return &m_active_delete;
+ }
+
+ for (const auto& del_info : m_delete_queue) {
+ if (del_info->match(image_name)) {
+ return &del_info;
+ }
+ }
+
+ for (const auto& del_info : m_failed_queue) {
+ if (del_info->match(image_name)) {
+ return &del_info;
+ }
+ }
+
+ return nullptr;
+}
+
void ImageDeleter::print_status(Formatter *f, stringstream *ss) {
dout(20) << "enter" << dendl;
public:
static const int EISPRM = 1000;
- ImageDeleter(RadosRef local_cluster, ContextWQ *work_queue,
- SafeTimer *timer, Mutex *timer_lock);
+ ImageDeleter(ContextWQ *work_queue, SafeTimer *timer, Mutex *timer_lock);
~ImageDeleter();
ImageDeleter(const ImageDeleter&) = delete;
ImageDeleter& operator=(const ImageDeleter&) = delete;
- void schedule_image_delete(uint64_t local_pool_id,
+ void schedule_image_delete(RadosRef local_rados,
+ uint64_t local_pool_id,
const std::string& local_image_id,
const std::string& local_image_name,
const std::string& global_image_id);
};
struct DeleteInfo {
+ RadosRef local_rados;
uint64_t local_pool_id;
std::string local_image_id;
std::string local_image_name;
bool notify_on_failed_retry;
Context *on_delete;
- DeleteInfo(uint64_t local_pool_id, const std::string& local_image_id,
+ DeleteInfo(RadosRef local_rados, uint64_t local_pool_id,
+ const std::string& local_image_id,
const std::string& local_image_name,
const std::string& global_image_id) :
- local_pool_id(local_pool_id), local_image_id(local_image_id),
- local_image_name(local_image_name), global_image_id(global_image_id),
- error_code(0), retries(0), notify_on_failed_retry(true),
- on_delete(nullptr) {
+ local_rados(local_rados), local_pool_id(local_pool_id),
+ local_image_id(local_image_id), local_image_name(local_image_name),
+ global_image_id(global_image_id), error_code(0), retries(0),
+ notify_on_failed_retry(true), on_delete(nullptr) {
}
bool match(const std::string& image_name) {
bool print_failure_info=false);
};
- RadosRef m_local;
atomic_t m_running;
ContextWQ *m_work_queue;
Mutex m_delete_lock;
Cond m_delete_queue_cond;
- unique_ptr<DeleteInfo> curr_deletion;
+ unique_ptr<DeleteInfo> m_active_delete;
ImageDeleterThread m_image_deleter_thread;
int image_has_snapshots_and_children(librados::IoCtx *ioctx,
std::string& image_id,
bool *has_snapshots);
+
+ void complete_active_delete(int r);
void enqueue_failed_delete(int error_code);
void retry_failed_deletions();
- unique_ptr<DeleteInfo> const* find_delete_info(
- const std::string& image_name) {
- assert(m_delete_lock.is_locked());
-
- if (curr_deletion && curr_deletion->match(image_name)) {
- return &curr_deletion;
- }
-
- for (const auto& del_info : m_delete_queue) {
- if (del_info->match(image_name)) {
- return &del_info;
- }
- }
-
- for (const auto& del_info : m_failed_queue) {
- if (del_info->match(image_name)) {
- return &del_info;
- }
- }
-
- return nullptr;
- }
+ unique_ptr<DeleteInfo> const* find_delete_info(const std::string& image_name);
};
} // namespace mirror
}
if (m_stopping_for_resync) {
- m_image_deleter->schedule_image_delete(m_local_pool_id,
+ m_image_deleter->schedule_image_delete(m_local,
+ m_local_pool_id,
m_local_image_id,
m_local_image_name,
m_global_image_id);
// TODO: make interval configurable
m_local_cluster_watcher.reset(new ClusterWatcher(m_local, m_lock));
- m_image_deleter.reset(new ImageDeleter(m_local, m_threads->work_queue,
+ m_image_deleter.reset(new ImageDeleter(m_threads->work_queue,
m_threads->timer,
&m_threads->timer_lock));
for (auto &image : m_init_images) {
dout(20) << "scheduling the deletion of init image: "
<< image.name << dendl;
- m_image_deleter->schedule_image_delete(m_local_pool_id, image.id,
- image.name, image.global_id);
+ m_image_deleter->schedule_image_delete(m_local_rados, m_local_pool_id,
+ image.id, image.name,
+ image.global_id);
}
m_init_images.clear();
}
if (!m_stopping.read()) {
dout(20) << "scheduling delete" << dendl;
m_image_deleter->schedule_image_delete(
+ m_local_rados,
image_replayer->get_local_pool_id(),
image_replayer->get_local_image_id(),
image_replayer->get_local_image_name(),
[&image_replayer, this] (int r) {
if (!m_stopping.read()) {
m_image_deleter->schedule_image_delete(
+ m_local_rados,
image_replayer->get_local_pool_id(),
image_replayer->get_local_image_id(),
image_replayer->get_local_image_name(),