initial code repo
[stor4nfv.git] / src / ceph / src / librbd / ImageWatcher.h
diff --git a/src/ceph/src/librbd/ImageWatcher.h b/src/ceph/src/librbd/ImageWatcher.h
new file mode 100644 (file)
index 0000000..5e30c8e
--- /dev/null
@@ -0,0 +1,255 @@
+// -*- 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 <set>
+#include <string>
+#include <utility>
+
+class entity_name_t;
+
+namespace librbd {
+
+namespace watcher {
+namespace util {
+template <typename> struct HandlePayloadVisitor;
+}
+}
+
+class ImageCtx;
+template <typename> class TaskFinisher;
+
+template <typename ImageCtxT = ImageCtx>
+class ImageWatcher : public Watcher {
+  friend struct watcher::util::HandlePayloadVisitor<ImageWatcher<ImageCtxT>>;
+
+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<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_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;
+
+  RWLock m_async_request_lock;
+  std::map<watch_notify::AsyncRequestId, AsyncRequest> m_async_requests;
+  std::set<watch_notify::AsyncRequestId> 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<librbd::ImageCtx>;
+
+#endif // CEPH_LIBRBD_IMAGE_WATCHER_H