]>
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" | |
f67539c2 TL |
10 | #include "common/environment.h" |
11 | #include "common/hostname.h" | |
12 | #include "librbd/plugin/Api.h" | |
13 | ||
14 | #undef dout_subsys | |
15 | #define dout_subsys ceph_subsys_rbd_pwl | |
16 | #undef dout_prefix | |
17 | #define dout_prefix *_dout << "librbd::cache::pwl::ImageCacheState: " \ | |
18 | << __func__ << ": " | |
19 | ||
20 | namespace librbd { | |
21 | namespace cache { | |
22 | namespace pwl { | |
23 | ||
20effc67 TL |
24 | using namespace std; |
25 | ||
33c7a0ef TL |
26 | template <typename I> |
27 | void ImageCacheState<I>::init_from_config() { | |
28 | ldout(m_image_ctx->cct, 20) << dendl; | |
29 | ||
30 | present = false; | |
31 | empty = true; | |
32 | clean = true; | |
33 | host = ""; | |
34 | path = ""; | |
35 | ConfigProxy &config = m_image_ctx->config; | |
36 | mode = config.get_val<std::string>("rbd_persistent_cache_mode"); | |
37 | size = 0; | |
f67539c2 | 38 | } |
f67539c2 TL |
39 | |
40 | template <typename I> | |
33c7a0ef TL |
41 | bool ImageCacheState<I>::init_from_metadata(json_spirit::mValue& json_root) { |
42 | ldout(m_image_ctx->cct, 20) << dendl; | |
43 | ||
44 | try { | |
45 | auto& o = json_root.get_obj(); | |
46 | present = o["present"].get_bool(); | |
47 | empty = o["empty"].get_bool(); | |
48 | clean = o["clean"].get_bool(); | |
49 | host = o["host"].get_str(); | |
50 | path = o["path"].get_str(); | |
51 | mode = o["mode"].get_str(); | |
52 | size = o["size"].get_uint64(); | |
53 | } catch (std::runtime_error& e) { | |
54 | lderr(m_image_ctx->cct) << "failed to parse cache state: " << e.what() | |
f67539c2 | 55 | << dendl; |
33c7a0ef TL |
56 | return false; |
57 | } | |
f67539c2 | 58 | |
33c7a0ef | 59 | return true; |
f67539c2 TL |
60 | } |
61 | ||
62 | template <typename I> | |
63 | void ImageCacheState<I>::write_image_cache_state(Context *on_finish) { | |
33c7a0ef | 64 | stats_timestamp = ceph_clock_now(); |
f67539c2 | 65 | std::shared_lock owner_lock{m_image_ctx->owner_lock}; |
33c7a0ef TL |
66 | json_spirit::mObject o; |
67 | o["present"] = present; | |
68 | o["empty"] = empty; | |
69 | o["clean"] = clean; | |
70 | o["host"] = host; | |
71 | o["path"] = path; | |
72 | o["mode"] = mode; | |
73 | o["size"] = size; | |
74 | o["stats_timestamp"] = stats_timestamp.sec(); | |
75 | o["allocated_bytes"] = allocated_bytes; | |
76 | o["cached_bytes"] = cached_bytes; | |
77 | o["dirty_bytes"] = dirty_bytes; | |
78 | o["free_bytes"] = free_bytes; | |
79 | o["hits_full"] = hits_full; | |
80 | o["hits_partial"] = hits_partial; | |
81 | o["misses"] = misses; | |
82 | o["hit_bytes"] = hit_bytes; | |
83 | o["miss_bytes"] = miss_bytes; | |
84 | std::string image_state_json = json_spirit::write(o); | |
f67539c2 TL |
85 | |
86 | ldout(m_image_ctx->cct, 20) << __func__ << " Store state: " | |
87 | << image_state_json << dendl; | |
33c7a0ef | 88 | m_plugin_api.execute_image_metadata_set(m_image_ctx, PERSISTENT_CACHE_STATE, |
f67539c2 TL |
89 | image_state_json, on_finish); |
90 | } | |
91 | ||
92 | template <typename I> | |
93 | void ImageCacheState<I>::clear_image_cache_state(Context *on_finish) { | |
94 | std::shared_lock owner_lock{m_image_ctx->owner_lock}; | |
95 | ldout(m_image_ctx->cct, 20) << __func__ << " Remove state: " << dendl; | |
96 | m_plugin_api.execute_image_metadata_remove( | |
33c7a0ef | 97 | m_image_ctx, PERSISTENT_CACHE_STATE, on_finish); |
f67539c2 TL |
98 | } |
99 | ||
100 | template <typename I> | |
101 | ImageCacheState<I>* ImageCacheState<I>::create_image_cache_state( | |
102 | I* image_ctx, plugin::Api<I>& plugin_api, int &r) { | |
103 | std::string cache_state_str; | |
104 | ImageCacheState<I>* cache_state = nullptr; | |
f67539c2 TL |
105 | |
106 | r = 0; | |
107 | bool dirty_cache = plugin_api.test_image_features(image_ctx, RBD_FEATURE_DIRTY_CACHE); | |
108 | if (dirty_cache) { | |
109 | cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid, | |
33c7a0ef | 110 | PERSISTENT_CACHE_STATE, &cache_state_str); |
f67539c2 TL |
111 | } |
112 | ||
b3b6e05e TL |
113 | ldout(image_ctx->cct, 20) << "image_cache_state: " << cache_state_str << dendl; |
114 | ||
f67539c2 TL |
115 | bool pwl_enabled = cache::util::is_pwl_enabled(*image_ctx); |
116 | bool cache_desired = pwl_enabled; | |
117 | cache_desired &= !image_ctx->read_only; | |
118 | cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_MIGRATING); | |
119 | cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_JOURNALING); | |
120 | cache_desired &= !image_ctx->old_format; | |
121 | ||
122 | if (!dirty_cache && !cache_desired) { | |
123 | ldout(image_ctx->cct, 20) << "Do not desire to use image cache." << dendl; | |
124 | } else if (dirty_cache && !cache_desired) { | |
125 | lderr(image_ctx->cct) << "There's a dirty cache, but RWL cache is disabled." | |
126 | << dendl; | |
127 | r = -EINVAL; | |
128 | }else if ((!dirty_cache || cache_state_str.empty()) && cache_desired) { | |
129 | cache_state = new ImageCacheState<I>(image_ctx, plugin_api); | |
33c7a0ef | 130 | cache_state->init_from_config(); |
f67539c2 TL |
131 | } else { |
132 | ceph_assert(!cache_state_str.empty()); | |
33c7a0ef TL |
133 | json_spirit::mValue json_root; |
134 | if (!json_spirit::read(cache_state_str.c_str(), json_root)) { | |
135 | lderr(image_ctx->cct) << "failed to parse cache state" << dendl; | |
f67539c2 TL |
136 | r = -EINVAL; |
137 | return nullptr; | |
138 | } | |
33c7a0ef TL |
139 | cache_state = new ImageCacheState<I>(image_ctx, plugin_api); |
140 | if (!cache_state->init_from_metadata(json_root)) { | |
141 | delete cache_state; | |
142 | r = -EINVAL; | |
143 | return nullptr; | |
144 | } | |
145 | if (!cache_state->present) { | |
146 | cache_state->init_from_config(); | |
f67539c2 TL |
147 | } |
148 | } | |
149 | return cache_state; | |
150 | } | |
151 | ||
152 | template <typename I> | |
153 | ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state( | |
154 | I* image_ctx, plugin::Api<I>& plugin_api) { | |
155 | ImageCacheState<I>* cache_state = nullptr; | |
156 | string cache_state_str; | |
157 | cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid, | |
33c7a0ef | 158 | PERSISTENT_CACHE_STATE, &cache_state_str); |
f67539c2 | 159 | if (!cache_state_str.empty()) { |
33c7a0ef TL |
160 | // ignore errors, best effort |
161 | cache_state = new ImageCacheState<I>(image_ctx, plugin_api); | |
162 | json_spirit::mValue json_root; | |
163 | if (!json_spirit::read(cache_state_str.c_str(), json_root)) { | |
164 | lderr(image_ctx->cct) << "failed to parse cache state" << dendl; | |
f67539c2 | 165 | } else { |
33c7a0ef | 166 | cache_state->init_from_metadata(json_root); |
f67539c2 TL |
167 | } |
168 | } | |
169 | return cache_state; | |
170 | } | |
171 | ||
172 | template <typename I> | |
173 | bool ImageCacheState<I>::is_valid() { | |
174 | if (this->present && | |
175 | (host.compare(ceph_get_short_hostname()) != 0)) { | |
176 | auto cleanstring = "dirty"; | |
177 | if (this->clean) { | |
178 | cleanstring = "clean"; | |
179 | } | |
180 | lderr(m_image_ctx->cct) << "An image cache (RWL) remains on another host " | |
181 | << host << " which is " << cleanstring | |
182 | << ". Flush/close the image there to remove the " | |
183 | << "image cache" << dendl; | |
184 | return false; | |
185 | } | |
186 | return true; | |
187 | } | |
188 | ||
189 | } // namespace pwl | |
190 | } // namespace cache | |
191 | } // namespace librbd | |
192 | ||
193 | template class librbd::cache::pwl::ImageCacheState<librbd::ImageCtx>; |