]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/cache/pwl/ImageCacheState.cc
import ceph pacific 16.2.5
[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 cache_type = f["cache_type"];
58 host = f["pwl_host"];
59 path = f["pwl_path"];
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;
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 ldout(image_ctx->cct, 20) << "image_cache_state: " << cache_state_str << dendl;
118
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"];
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);
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>;