]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/cache/pwl/ImageCacheState.cc
import ceph quincy 17.2.1
[ceph.git] / ceph / src / librbd / cache / pwl / ImageCacheState.cc
CommitLineData
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
20namespace librbd {
21namespace cache {
22namespace pwl {
23
20effc67
TL
24using namespace std;
25
33c7a0ef
TL
26template <typename I>
27void 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
40template <typename I>
33c7a0ef
TL
41bool 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
62template <typename I>
63void 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
92template <typename I>
93void 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
100template <typename I>
101ImageCacheState<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
152template <typename I>
153ImageCacheState<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
172template <typename I>
173bool 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
193template class librbd::cache::pwl::ImageCacheState<librbd::ImageCtx>;