]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "librbd/cache/Types.h" | |
5 | #include "librbd/cache/Utils.h" | |
6 | #include "librbd/cache/pwl/ImageCacheState.h" | |
7 | #include "librbd/ImageCtx.h" | |
8 | #include "librbd/Operations.h" | |
9 | #include "common/config_proxy.h" | |
10 | #include "common/ceph_json.h" | |
11 | #include "common/environment.h" | |
12 | #include "common/hostname.h" | |
13 | #include "librbd/plugin/Api.h" | |
14 | ||
15 | #undef dout_subsys | |
16 | #define dout_subsys ceph_subsys_rbd_pwl | |
17 | #undef dout_prefix | |
18 | #define dout_prefix *_dout << "librbd::cache::pwl::ImageCacheState: " \ | |
19 | << __func__ << ": " | |
20 | ||
21 | namespace librbd { | |
22 | namespace cache { | |
23 | namespace pwl { | |
24 | ||
25 | namespace { | |
26 | bool get_json_format(const std::string& s, JSONFormattable *f) { | |
27 | JSONParser p; | |
28 | bool success = p.parse(s.c_str(), s.size()); | |
29 | if (success) { | |
30 | decode_json_obj(*f, &p); | |
31 | } | |
32 | return success; | |
33 | } | |
34 | } // namespace | |
35 | ||
36 | template <typename I> | |
37 | ImageCacheState<I>::ImageCacheState(I *image_ctx, plugin::Api<I>& plugin_api) : | |
38 | m_image_ctx(image_ctx), m_plugin_api(plugin_api) { | |
39 | ldout(image_ctx->cct, 20) << "Initialize RWL cache state with config data. " | |
40 | << dendl; | |
41 | ||
42 | ConfigProxy &config = image_ctx->config; | |
43 | log_periodic_stats = config.get_val<bool>("rbd_persistent_cache_log_periodic_stats"); | |
44 | cache_type = config.get_val<std::string>("rbd_persistent_cache_mode"); | |
45 | } | |
46 | ||
47 | template <typename I> | |
48 | ImageCacheState<I>::ImageCacheState( | |
49 | I *image_ctx, JSONFormattable &f, plugin::Api<I>& plugin_api) : | |
50 | m_image_ctx(image_ctx), m_plugin_api(plugin_api) { | |
51 | ldout(image_ctx->cct, 20) << "Initialize RWL cache state with data from " | |
52 | << "server side"<< dendl; | |
53 | ||
54 | present = (bool)f["present"]; | |
55 | empty = (bool)f["empty"]; | |
56 | clean = (bool)f["clean"]; | |
b3b6e05e TL |
57 | cache_type = f["cache_type"]; |
58 | host = f["pwl_host"]; | |
59 | path = f["pwl_path"]; | |
f67539c2 TL |
60 | uint64_t pwl_size; |
61 | std::istringstream iss(f["pwl_size"]); | |
62 | iss >> pwl_size; | |
63 | size = pwl_size; | |
64 | ||
65 | // Others from config | |
66 | ConfigProxy &config = image_ctx->config; | |
67 | log_periodic_stats = config.get_val<bool>("rbd_persistent_cache_log_periodic_stats"); | |
68 | } | |
69 | ||
70 | template <typename I> | |
71 | void ImageCacheState<I>::write_image_cache_state(Context *on_finish) { | |
72 | std::shared_lock owner_lock{m_image_ctx->owner_lock}; | |
73 | JSONFormattable f; | |
74 | ::encode_json(IMAGE_CACHE_STATE.c_str(), *this, &f); | |
75 | std::ostringstream oss; | |
76 | f.flush(oss); | |
77 | std::string image_state_json = oss.str(); | |
78 | ||
79 | ldout(m_image_ctx->cct, 20) << __func__ << " Store state: " | |
80 | << image_state_json << dendl; | |
81 | m_plugin_api.execute_image_metadata_set(m_image_ctx, IMAGE_CACHE_STATE, | |
82 | image_state_json, on_finish); | |
83 | } | |
84 | ||
85 | template <typename I> | |
86 | void ImageCacheState<I>::clear_image_cache_state(Context *on_finish) { | |
87 | std::shared_lock owner_lock{m_image_ctx->owner_lock}; | |
88 | ldout(m_image_ctx->cct, 20) << __func__ << " Remove state: " << dendl; | |
89 | m_plugin_api.execute_image_metadata_remove( | |
90 | m_image_ctx, IMAGE_CACHE_STATE, on_finish); | |
91 | } | |
92 | ||
93 | template <typename I> | |
94 | void ImageCacheState<I>::dump(ceph::Formatter *f) const { | |
95 | ::encode_json("present", present, f); | |
96 | ::encode_json("empty", empty, f); | |
97 | ::encode_json("clean", clean, f); | |
98 | ::encode_json("cache_type", cache_type, f); | |
99 | ::encode_json("pwl_host", host, f); | |
100 | ::encode_json("pwl_path", path, f); | |
101 | ::encode_json("pwl_size", size, f); | |
102 | } | |
103 | ||
104 | template <typename I> | |
105 | ImageCacheState<I>* ImageCacheState<I>::create_image_cache_state( | |
106 | I* image_ctx, plugin::Api<I>& plugin_api, int &r) { | |
107 | std::string cache_state_str; | |
108 | ImageCacheState<I>* cache_state = nullptr; | |
f67539c2 TL |
109 | |
110 | r = 0; | |
111 | bool dirty_cache = plugin_api.test_image_features(image_ctx, RBD_FEATURE_DIRTY_CACHE); | |
112 | if (dirty_cache) { | |
113 | cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid, | |
114 | IMAGE_CACHE_STATE, &cache_state_str); | |
115 | } | |
116 | ||
b3b6e05e TL |
117 | ldout(image_ctx->cct, 20) << "image_cache_state: " << cache_state_str << dendl; |
118 | ||
f67539c2 TL |
119 | bool pwl_enabled = cache::util::is_pwl_enabled(*image_ctx); |
120 | bool cache_desired = pwl_enabled; | |
121 | cache_desired &= !image_ctx->read_only; | |
122 | cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_MIGRATING); | |
123 | cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_JOURNALING); | |
124 | cache_desired &= !image_ctx->old_format; | |
125 | ||
126 | if (!dirty_cache && !cache_desired) { | |
127 | ldout(image_ctx->cct, 20) << "Do not desire to use image cache." << dendl; | |
128 | } else if (dirty_cache && !cache_desired) { | |
129 | lderr(image_ctx->cct) << "There's a dirty cache, but RWL cache is disabled." | |
130 | << dendl; | |
131 | r = -EINVAL; | |
132 | }else if ((!dirty_cache || cache_state_str.empty()) && cache_desired) { | |
133 | cache_state = new ImageCacheState<I>(image_ctx, plugin_api); | |
134 | } else { | |
135 | ceph_assert(!cache_state_str.empty()); | |
136 | JSONFormattable f; | |
137 | bool success = get_json_format(cache_state_str, &f); | |
138 | if (!success) { | |
139 | lderr(image_ctx->cct) << "Failed to parse cache state: " | |
140 | << cache_state_str << dendl; | |
141 | r = -EINVAL; | |
142 | return nullptr; | |
143 | } | |
144 | ||
145 | bool cache_exists = (bool)f["present"]; | |
b3b6e05e TL |
146 | if (!cache_exists) { |
147 | cache_state = new ImageCacheState<I>(image_ctx, plugin_api); | |
148 | } else { | |
149 | cache_state = new ImageCacheState<I>(image_ctx, f, plugin_api); | |
f67539c2 TL |
150 | } |
151 | } | |
152 | return cache_state; | |
153 | } | |
154 | ||
155 | template <typename I> | |
156 | ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state( | |
157 | I* image_ctx, plugin::Api<I>& plugin_api) { | |
158 | ImageCacheState<I>* cache_state = nullptr; | |
159 | string cache_state_str; | |
160 | cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid, | |
161 | IMAGE_CACHE_STATE, &cache_state_str); | |
162 | if (!cache_state_str.empty()) { | |
163 | JSONFormattable f; | |
164 | bool success = get_json_format(cache_state_str, &f); | |
165 | if (!success) { | |
166 | cache_state = new ImageCacheState<I>(image_ctx, plugin_api); | |
167 | } else { | |
168 | cache_state = new ImageCacheState<I>(image_ctx, f, plugin_api); | |
169 | } | |
170 | } | |
171 | return cache_state; | |
172 | } | |
173 | ||
174 | template <typename I> | |
175 | bool ImageCacheState<I>::is_valid() { | |
176 | if (this->present && | |
177 | (host.compare(ceph_get_short_hostname()) != 0)) { | |
178 | auto cleanstring = "dirty"; | |
179 | if (this->clean) { | |
180 | cleanstring = "clean"; | |
181 | } | |
182 | lderr(m_image_ctx->cct) << "An image cache (RWL) remains on another host " | |
183 | << host << " which is " << cleanstring | |
184 | << ". Flush/close the image there to remove the " | |
185 | << "image cache" << dendl; | |
186 | return false; | |
187 | } | |
188 | return true; | |
189 | } | |
190 | ||
191 | } // namespace pwl | |
192 | } // namespace cache | |
193 | } // namespace librbd | |
194 | ||
195 | template class librbd::cache::pwl::ImageCacheState<librbd::ImageCtx>; |