]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/cache/pwl/ImageCacheState.cc
2c6117d9e2ff3bd8ec73725e866555b09b264458
[ceph.git] / ceph / src / librbd / cache / pwl / ImageCacheState.cc
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"];
57 host = (string)f["pwl_host"];
58 path = (string)f["pwl_path"];
59 uint64_t pwl_size;
60 std::istringstream iss(f["pwl_size"]);
61 iss >> pwl_size;
62 size = pwl_size;
63
64 // Others from config
65 ConfigProxy &config = image_ctx->config;
66 log_periodic_stats = config.get_val<bool>("rbd_persistent_cache_log_periodic_stats");
67 }
68
69 template <typename I>
70 void ImageCacheState<I>::write_image_cache_state(Context *on_finish) {
71 std::shared_lock owner_lock{m_image_ctx->owner_lock};
72 JSONFormattable f;
73 ::encode_json(IMAGE_CACHE_STATE.c_str(), *this, &f);
74 std::ostringstream oss;
75 f.flush(oss);
76 std::string image_state_json = oss.str();
77
78 ldout(m_image_ctx->cct, 20) << __func__ << " Store state: "
79 << image_state_json << dendl;
80 m_plugin_api.execute_image_metadata_set(m_image_ctx, IMAGE_CACHE_STATE,
81 image_state_json, on_finish);
82 }
83
84 template <typename I>
85 void ImageCacheState<I>::clear_image_cache_state(Context *on_finish) {
86 std::shared_lock owner_lock{m_image_ctx->owner_lock};
87 ldout(m_image_ctx->cct, 20) << __func__ << " Remove state: " << dendl;
88 m_plugin_api.execute_image_metadata_remove(
89 m_image_ctx, IMAGE_CACHE_STATE, on_finish);
90 }
91
92 template <typename I>
93 void ImageCacheState<I>::dump(ceph::Formatter *f) const {
94 ::encode_json("present", present, f);
95 ::encode_json("empty", empty, f);
96 ::encode_json("clean", clean, f);
97 ::encode_json("cache_type", cache_type, f);
98 ::encode_json("pwl_host", host, f);
99 ::encode_json("pwl_path", path, f);
100 ::encode_json("pwl_size", size, f);
101 }
102
103 template <typename I>
104 ImageCacheState<I>* ImageCacheState<I>::create_image_cache_state(
105 I* image_ctx, plugin::Api<I>& plugin_api, int &r) {
106 std::string cache_state_str;
107 ImageCacheState<I>* cache_state = nullptr;
108 ldout(image_ctx->cct, 20) << "image_cache_state:" << cache_state_str << dendl;
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
117 bool pwl_enabled = cache::util::is_pwl_enabled(*image_ctx);
118 bool cache_desired = pwl_enabled;
119 cache_desired &= !image_ctx->read_only;
120 cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_MIGRATING);
121 cache_desired &= !plugin_api.test_image_features(image_ctx, RBD_FEATURE_JOURNALING);
122 cache_desired &= !image_ctx->old_format;
123
124 if (!dirty_cache && !cache_desired) {
125 ldout(image_ctx->cct, 20) << "Do not desire to use image cache." << dendl;
126 } else if (dirty_cache && !cache_desired) {
127 lderr(image_ctx->cct) << "There's a dirty cache, but RWL cache is disabled."
128 << dendl;
129 r = -EINVAL;
130 }else if ((!dirty_cache || cache_state_str.empty()) && cache_desired) {
131 cache_state = new ImageCacheState<I>(image_ctx, plugin_api);
132 } else {
133 ceph_assert(!cache_state_str.empty());
134 JSONFormattable f;
135 bool success = get_json_format(cache_state_str, &f);
136 if (!success) {
137 lderr(image_ctx->cct) << "Failed to parse cache state: "
138 << cache_state_str << dendl;
139 r = -EINVAL;
140 return nullptr;
141 }
142
143 bool cache_exists = (bool)f["present"];
144 int cache_type = (int)f["cache_type"];
145
146 switch (cache_type) {
147 case IMAGE_CACHE_TYPE_SSD:
148 case IMAGE_CACHE_TYPE_RWL:
149 if (!cache_exists) {
150 cache_state = new ImageCacheState<I>(image_ctx, plugin_api);
151 } else {
152 cache_state = new ImageCacheState<I>(image_ctx, f, plugin_api);
153 }
154 break;
155 default:
156 r = -EINVAL;
157 }
158 }
159 return cache_state;
160 }
161
162 template <typename I>
163 ImageCacheState<I>* ImageCacheState<I>::get_image_cache_state(
164 I* image_ctx, plugin::Api<I>& plugin_api) {
165 ImageCacheState<I>* cache_state = nullptr;
166 string cache_state_str;
167 cls_client::metadata_get(&image_ctx->md_ctx, image_ctx->header_oid,
168 IMAGE_CACHE_STATE, &cache_state_str);
169 if (!cache_state_str.empty()) {
170 JSONFormattable f;
171 bool success = get_json_format(cache_state_str, &f);
172 if (!success) {
173 cache_state = new ImageCacheState<I>(image_ctx, plugin_api);
174 } else {
175 cache_state = new ImageCacheState<I>(image_ctx, f, plugin_api);
176 }
177 }
178 return cache_state;
179 }
180
181 template <typename I>
182 bool ImageCacheState<I>::is_valid() {
183 if (this->present &&
184 (host.compare(ceph_get_short_hostname()) != 0)) {
185 auto cleanstring = "dirty";
186 if (this->clean) {
187 cleanstring = "clean";
188 }
189 lderr(m_image_ctx->cct) << "An image cache (RWL) remains on another host "
190 << host << " which is " << cleanstring
191 << ". Flush/close the image there to remove the "
192 << "image cache" << dendl;
193 return false;
194 }
195 return true;
196 }
197
198 } // namespace pwl
199 } // namespace cache
200 } // namespace librbd
201
202 template class librbd::cache::pwl::ImageCacheState<librbd::ImageCtx>;