// -*- 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/Mutex.h" #include "common/RWLock.h" #include "include/Context.h" #include "include/rbd/librbd.hpp" #include "librbd/Watcher.h" #include "librbd/WatchNotifyTypes.h" #include #include #include class entity_name_t; namespace librbd { namespace watcher { namespace util { template struct HandlePayloadVisitor; } } class ImageCtx; template class TaskFinisher; template class ImageWatcher : public Watcher { friend struct watcher::util::HandlePayloadVisitor>; 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(const cls::rbd::SnapshotNamespace &snap_namespace, const std::string &snap_name, Context *on_finish); void notify_snap_rename(const snapid_t &src_snap_id, const std::string &dst_snap_name, Context *on_finish); void notify_snap_remove(const cls::rbd::SnapshotNamespace &snap_namespace, const std::string &snap_name, Context *on_finish); void notify_snap_protect(const cls::rbd::SnapshotNamespace &snap_namespace, const std::string &snap_name, Context *on_finish); void notify_snap_unprotect(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(const std::string &image_name, Context *on_finish); void notify_update_features(uint64_t features, bool enabled, 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); private: enum TaskCode { TASK_CODE_REQUEST_LOCK, TASK_CODE_CANCEL_ASYNC_REQUESTS, TASK_CODE_REREGISTER_WATCH, TASK_CODE_ASYNC_REQUEST, TASK_CODE_ASYNC_PROGRESS }; typedef std::pair 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_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 *m_task_finisher; RWLock m_async_request_lock; std::map m_async_requests; std::set m_async_pending; Mutex m_owner_client_id_lock; watch_notify::ClientId m_owner_client_id; 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(const watch_notify::Payload& payload, Context *on_finish); Context *remove_async_request(const watch_notify::AsyncRequestId &id); 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, const 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); 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::UnknownPayload& payload, C_NotifyAck *ctx); void process_payload(uint64_t notify_id, uint64_t handle, const 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(const watch_notify::Payload& payload, Context *ctx = nullptr); }; } // namespace librbd extern template class librbd::ImageWatcher; #endif // CEPH_LIBRBD_IMAGE_WATCHER_H