summaryrefslogtreecommitdiffstats
path: root/src/librbd/ImageWatcher.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/librbd/ImageWatcher.h313
1 files changed, 313 insertions, 0 deletions
diff --git a/src/librbd/ImageWatcher.h b/src/librbd/ImageWatcher.h
new file mode 100644
index 000000000..cda9a246e
--- /dev/null
+++ b/src/librbd/ImageWatcher.h
@@ -0,0 +1,313 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_LIBRBD_IMAGE_WATCHER_H
+#define CEPH_LIBRBD_IMAGE_WATCHER_H
+
+#include "cls/rbd/cls_rbd_types.h"
+#include "common/AsyncOpTracker.h"
+#include "common/ceph_mutex.h"
+#include "include/Context.h"
+#include "include/rbd/librbd.hpp"
+#include "librbd/Operations.h"
+#include "librbd/Watcher.h"
+#include "librbd/WatchNotifyTypes.h"
+#include "librbd/exclusive_lock/Policy.h"
+#include "librbd/internal.h"
+#include <functional>
+#include <set>
+#include <string>
+#include <utility>
+
+class entity_name_t;
+
+namespace librbd {
+
+class ImageCtx;
+template <typename> class TaskFinisher;
+
+template <typename ImageCtxT = ImageCtx>
+class ImageWatcher : public Watcher {
+public:
+ ImageWatcher(ImageCtxT& image_ctx);
+ ~ImageWatcher() override;
+
+ void unregister_watch(Context *on_finish) override;
+ void block_notifies(Context *on_finish) override;
+
+ void notify_flatten(uint64_t request_id, ProgressContext &prog_ctx,
+ Context *on_finish);
+ void notify_resize(uint64_t request_id, uint64_t size, bool allow_shrink,
+ ProgressContext &prog_ctx, Context *on_finish);
+ void notify_snap_create(uint64_t request_id,
+ const cls::rbd::SnapshotNamespace &snap_namespace,
+ const std::string &snap_name,
+ uint64_t flags,
+ ProgressContext &prog_ctx,
+ Context *on_finish);
+ void notify_snap_rename(uint64_t request_id,
+ const snapid_t &src_snap_id,
+ const std::string &dst_snap_name,
+ Context *on_finish);
+ void notify_snap_remove(uint64_t request_id,
+ const cls::rbd::SnapshotNamespace &snap_namespace,
+ const std::string &snap_name,
+ Context *on_finish);
+ void notify_snap_protect(uint64_t request_id,
+ const cls::rbd::SnapshotNamespace &snap_namespace,
+ const std::string &snap_name,
+ Context *on_finish);
+ void notify_snap_unprotect(uint64_t request_id,
+ const cls::rbd::SnapshotNamespace &snap_namespace,
+ const std::string &snap_name,
+ Context *on_finish);
+ void notify_rebuild_object_map(uint64_t request_id,
+ ProgressContext &prog_ctx, Context *on_finish);
+ void notify_rename(uint64_t request_id,
+ const std::string &image_name, Context *on_finish);
+
+ void notify_update_features(uint64_t request_id,
+ uint64_t features, bool enabled,
+ Context *on_finish);
+
+ void notify_migrate(uint64_t request_id, ProgressContext &prog_ctx,
+ Context *on_finish);
+
+ void notify_sparsify(uint64_t request_id, size_t sparse_size,
+ ProgressContext &prog_ctx, Context *on_finish);
+
+ void notify_acquired_lock();
+ void notify_released_lock();
+ void notify_request_lock();
+
+ void notify_header_update(Context *on_finish);
+ static void notify_header_update(librados::IoCtx &io_ctx,
+ const std::string &oid);
+
+ void notify_quiesce(uint64_t *request_id, ProgressContext &prog_ctx,
+ Context *on_finish);
+ void notify_unquiesce(uint64_t request_id, Context *on_finish);
+
+ void notify_metadata_set(uint64_t request_id,
+ const std::string &key, const std::string &value,
+ Context *on_finish);
+ void notify_metadata_remove(uint64_t request_id,
+ const std::string &key, Context *on_finish);
+
+private:
+ enum TaskCode {
+ TASK_CODE_REQUEST_LOCK,
+ TASK_CODE_CANCEL_ASYNC_REQUESTS,
+ TASK_CODE_REREGISTER_WATCH,
+ TASK_CODE_ASYNC_REQUEST,
+ TASK_CODE_ASYNC_PROGRESS,
+ TASK_CODE_QUIESCE,
+ };
+
+ typedef std::pair<Context *, ProgressContext *> AsyncRequest;
+
+ class Task {
+ public:
+ Task(TaskCode task_code) : m_task_code(task_code) {}
+ Task(TaskCode task_code, const watch_notify::AsyncRequestId &id)
+ : m_task_code(task_code), m_async_request_id(id) {}
+
+ inline bool operator<(const Task& rhs) const {
+ if (m_task_code != rhs.m_task_code) {
+ return m_task_code < rhs.m_task_code;
+ } else if ((m_task_code == TASK_CODE_ASYNC_REQUEST ||
+ m_task_code == TASK_CODE_ASYNC_PROGRESS ||
+ m_task_code == TASK_CODE_QUIESCE) &&
+ m_async_request_id != rhs.m_async_request_id) {
+ return m_async_request_id < rhs.m_async_request_id;
+ }
+ return false;
+ }
+ private:
+ TaskCode m_task_code;
+ watch_notify::AsyncRequestId m_async_request_id;
+ };
+
+ class RemoteProgressContext : public ProgressContext {
+ public:
+ RemoteProgressContext(ImageWatcher &image_watcher,
+ const watch_notify::AsyncRequestId &id)
+ : m_image_watcher(image_watcher), m_async_request_id(id)
+ {
+ }
+
+ int update_progress(uint64_t offset, uint64_t total) override {
+ m_image_watcher.schedule_async_progress(m_async_request_id, offset,
+ total);
+ return 0;
+ }
+
+ private:
+ ImageWatcher &m_image_watcher;
+ watch_notify::AsyncRequestId m_async_request_id;
+ };
+
+ class RemoteContext : public Context {
+ public:
+ RemoteContext(ImageWatcher &image_watcher,
+ const watch_notify::AsyncRequestId &id,
+ ProgressContext *prog_ctx)
+ : m_image_watcher(image_watcher), m_async_request_id(id),
+ m_prog_ctx(prog_ctx)
+ {
+ }
+
+ ~RemoteContext() override {
+ delete m_prog_ctx;
+ }
+
+ void finish(int r) override;
+
+ private:
+ ImageWatcher &m_image_watcher;
+ watch_notify::AsyncRequestId m_async_request_id;
+ ProgressContext *m_prog_ctx;
+ };
+
+ struct C_ProcessPayload;
+ struct C_ResponseMessage : public Context {
+ C_NotifyAck *notify_ack;
+
+ C_ResponseMessage(C_NotifyAck *notify_ack) : notify_ack(notify_ack) {
+ }
+ void finish(int r) override;
+ };
+
+ ImageCtxT &m_image_ctx;
+
+ TaskFinisher<Task> *m_task_finisher;
+
+ ceph::shared_mutex m_async_request_lock;
+ std::map<watch_notify::AsyncRequestId, AsyncRequest> m_async_requests;
+ std::set<watch_notify::AsyncRequestId> m_async_pending;
+ std::map<watch_notify::AsyncRequestId, int> m_async_complete;
+ std::set<std::pair<utime_t,
+ watch_notify::AsyncRequestId>> m_async_complete_expiration;
+
+ ceph::mutex m_owner_client_id_lock;
+ watch_notify::ClientId m_owner_client_id;
+
+ AsyncOpTracker m_async_op_tracker;
+
+ NoOpProgressContext m_no_op_prog_ctx;
+
+ void handle_register_watch(int r);
+
+ void schedule_cancel_async_requests();
+ void cancel_async_requests();
+
+ void set_owner_client_id(const watch_notify::ClientId &client_id);
+ watch_notify::ClientId get_client_id();
+
+ void handle_request_lock(int r);
+ void schedule_request_lock(bool use_timer, int timer_delay = -1);
+
+ void notify_lock_owner(watch_notify::Payload *payload, Context *on_finish);
+
+ bool is_new_request(const watch_notify::AsyncRequestId &id) const;
+ bool mark_async_request_complete(const watch_notify::AsyncRequestId &id,
+ int r);
+ Context *remove_async_request(const watch_notify::AsyncRequestId &id);
+ Context *remove_async_request(const watch_notify::AsyncRequestId &id,
+ ceph::shared_mutex &lock);
+ void schedule_async_request_timed_out(const watch_notify::AsyncRequestId &id);
+ void async_request_timed_out(const watch_notify::AsyncRequestId &id);
+ void notify_async_request(const watch_notify::AsyncRequestId &id,
+ watch_notify::Payload *payload,
+ ProgressContext& prog_ctx,
+ Context *on_finish);
+
+ void schedule_async_progress(const watch_notify::AsyncRequestId &id,
+ uint64_t offset, uint64_t total);
+ int notify_async_progress(const watch_notify::AsyncRequestId &id,
+ uint64_t offset, uint64_t total);
+ void schedule_async_complete(const watch_notify::AsyncRequestId &id, int r);
+ void notify_async_complete(const watch_notify::AsyncRequestId &id, int r);
+ void handle_async_complete(const watch_notify::AsyncRequestId &request, int r,
+ int ret_val);
+
+ int prepare_async_request(const watch_notify::AsyncRequestId& id,
+ bool* new_request, Context** ctx,
+ ProgressContext** prog_ctx);
+
+ Context *prepare_quiesce_request(const watch_notify::AsyncRequestId &request,
+ C_NotifyAck *ack_ctx);
+ void prepare_unquiesce_request(const watch_notify::AsyncRequestId &request);
+ void cancel_quiesce_requests();
+
+ void notify_quiesce(const watch_notify::AsyncRequestId &async_request_id,
+ size_t attempts, ProgressContext &prog_ctx,
+ Context *on_finish);
+
+ bool handle_operation_request(
+ const watch_notify::AsyncRequestId& async_request_id,
+ exclusive_lock::OperationRequestType request_type, Operation operation,
+ std::function<void(ProgressContext &prog_ctx, Context*)> execute,
+ C_NotifyAck *ack_ctx);
+
+ bool handle_payload(const watch_notify::HeaderUpdatePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::AcquiredLockPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::ReleasedLockPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::RequestLockPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::AsyncProgressPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::AsyncCompletePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::FlattenPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::ResizePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::SnapCreatePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::SnapRenamePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::SnapRemovePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::SnapProtectPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::SnapUnprotectPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::RebuildObjectMapPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::RenamePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::UpdateFeaturesPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::MigratePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::SparsifyPayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::QuiescePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::UnquiescePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::MetadataUpdatePayload& payload,
+ C_NotifyAck *ctx);
+ bool handle_payload(const watch_notify::UnknownPayload& payload,
+ C_NotifyAck *ctx);
+ void process_payload(uint64_t notify_id, uint64_t handle,
+ watch_notify::Payload *payload);
+
+ void handle_notify(uint64_t notify_id, uint64_t handle,
+ uint64_t notifier_id, bufferlist &bl) override;
+ void handle_error(uint64_t cookie, int err) override;
+ void handle_rewatch_complete(int r) override;
+
+ void send_notify(watch_notify::Payload *payload, Context *ctx = nullptr);
+
+};
+
+} // namespace librbd
+
+extern template class librbd::ImageWatcher<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_IMAGE_WATCHER_H