]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/cache/pwl/ImageCacheState.cc
import ceph pacific 16.2.5
[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"
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
21namespace librbd {
22namespace cache {
23namespace pwl {
24
25namespace {
26bool 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
36template <typename I>
37ImageCacheState<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
47template <typename I>
48ImageCacheState<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"];
b3b6e05e
TL
57 cache_type = f["cache_type"];
58 host = f["pwl_host"];
59 path = f["pwl_path"];
f67539c2
TL
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
70template <typename I>
71void 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
85template <typename I>
86void 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
93template <typename I>
94void 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
104template <typename I>
105ImageCacheState<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;
f67539c2
TL
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
b3b6e05e
TL
117 ldout(image_ctx->cct, 20) << "image_cache_state: " << cache_state_str << dendl;
118
f67539c2
TL
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"];
b3b6e05e
TL
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);
f67539c2
TL
150 }
151 }
152 return cache_state;
153}
154
155template <typename I>
156ImageCacheState<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
174template <typename I>
175bool 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
195template class librbd::cache::pwl::ImageCacheState<librbd::ImageCtx>;