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