summaryrefslogtreecommitdiffstats
path: root/src/librbd/ImageState.h
blob: 7f28d1eec712e2e4c0df6d220d5abefc3b788274 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#ifndef CEPH_LIBRBD_IMAGE_STATE_H
#define CEPH_LIBRBD_IMAGE_STATE_H

#include "include/int_types.h"
#include "common/Mutex.h"
#include <list>
#include <string>
#include <utility>
#include "cls/rbd/cls_rbd_types.h"

class Context;
class RWLock;

namespace librbd {

class ImageCtx;
class ImageUpdateWatchers;
class UpdateWatchCtx;

template <typename ImageCtxT = ImageCtx>
class ImageState {
public:
  ImageState(ImageCtxT *image_ctx);
  ~ImageState();

  int open(uint64_t flags);
  void open(uint64_t flags, Context *on_finish);

  int close();
  void close(Context *on_finish);

  void handle_update_notification();

  bool is_refresh_required() const;

  int refresh();
  int refresh_if_required();
  void refresh(Context *on_finish);

  void snap_set(uint64_t snap_id, Context *on_finish);

  void prepare_lock(Context *on_ready);
  void handle_prepare_lock_complete();

  int register_update_watcher(UpdateWatchCtx *watcher, uint64_t *handle);
  int unregister_update_watcher(uint64_t handle);
  void flush_update_watchers(Context *on_finish);
  void shut_down_update_watchers(Context *on_finish);

private:
  enum State {
    STATE_UNINITIALIZED,
    STATE_OPEN,
    STATE_CLOSED,
    STATE_OPENING,
    STATE_CLOSING,
    STATE_REFRESHING,
    STATE_SETTING_SNAP,
    STATE_PREPARING_LOCK
  };

  enum ActionType {
    ACTION_TYPE_OPEN,
    ACTION_TYPE_CLOSE,
    ACTION_TYPE_REFRESH,
    ACTION_TYPE_SET_SNAP,
    ACTION_TYPE_LOCK
  };

  struct Action {
    ActionType action_type;
    uint64_t refresh_seq = 0;
    uint64_t snap_id = CEPH_NOSNAP;
    Context *on_ready = nullptr;

    Action(ActionType action_type) : action_type(action_type) {
    }
    inline bool operator==(const Action &action) const {
      if (action_type != action.action_type) {
        return false;
      }
      switch (action_type) {
      case ACTION_TYPE_REFRESH:
        return (refresh_seq == action.refresh_seq);
      case ACTION_TYPE_SET_SNAP:
        return (snap_id == action.snap_id);
      case ACTION_TYPE_LOCK:
        return false;
      default:
        return true;
      }
    }
  };

  typedef std::list<Context *> Contexts;
  typedef std::pair<Action, Contexts> ActionContexts;
  typedef std::list<ActionContexts> ActionsContexts;

  ImageCtxT *m_image_ctx;
  State m_state;

  mutable Mutex m_lock;
  ActionsContexts m_actions_contexts;

  uint64_t m_last_refresh;
  uint64_t m_refresh_seq;

  ImageUpdateWatchers *m_update_watchers;

  uint64_t m_open_flags;

  bool is_transition_state() const;
  bool is_closed() const;

  const Action *find_pending_refresh() const;

  void append_context(const Action &action, Context *context);
  void execute_next_action_unlock();
  void execute_action_unlock(const Action &action, Context *context);
  void complete_action_unlock(State next_state, int r);

  void send_open_unlock();
  void handle_open(int r);

  void send_close_unlock();
  void handle_close(int r);

  void send_refresh_unlock();
  void handle_refresh(int r);

  void send_set_snap_unlock();
  void handle_set_snap(int r);

  void send_prepare_lock_unlock();

};

} // namespace librbd

extern template class librbd::ImageState<librbd::ImageCtx>;

#endif // CEPH_LIBRBD_IMAGE_STATE_H