]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_sync_trace.cc
import ceph pacific 16.2.5
[ceph.git] / ceph / src / rgw / rgw_sync_trace.cc
CommitLineData
11fdf7f2 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
11fdf7f2
TL
3
4#ifndef CEPH_RGW_SYNC_TRACE_H
5#define CEPH_RGW_SYNC_TRACE_H
6
7#include <regex>
8
9#include "common/debug.h"
10#include "common/ceph_json.h"
11
12#include "rgw_sync_trace.h"
13#include "rgw_rados.h"
9f95a23c 14#include "rgw_worker.h"
11fdf7f2
TL
15
16
17#define dout_context g_ceph_context
11fdf7f2
TL
18
19RGWSyncTraceNode::RGWSyncTraceNode(CephContext *_cct, uint64_t _handle,
20 const RGWSyncTraceNodeRef& _parent,
21 const string& _type, const string& _id) : cct(_cct),
22 parent(_parent),
23 type(_type),
24 id(_id),
25 handle(_handle),
26 history(cct->_conf->rgw_sync_trace_per_node_log_size)
27{
28 if (parent.get()) {
29 prefix = parent->get_prefix();
30 }
31
32 if (!type.empty()) {
33 prefix += type;
34 if (!id.empty()) {
35 prefix += "[" + id + "]";
36 }
37 prefix += ":";
38 }
39}
40
41void RGWSyncTraceNode::log(int level, const string& s)
42{
43 status = s;
44 history.push_back(status);
45 /* dump output on either rgw_sync, or rgw -- but only once */
46 if (cct->_conf->subsys.should_gather(ceph_subsys_rgw_sync, level)) {
47 lsubdout(cct, rgw_sync,
48 ceph::dout::need_dynamic(level)) << "RGW-SYNC:" << to_str() << dendl;
49 } else {
50 lsubdout(cct, rgw,
51 ceph::dout::need_dynamic(level)) << "RGW-SYNC:" << to_str() << dendl;
52 }
53}
54
55
56class RGWSyncTraceServiceMapThread : public RGWRadosThread {
57 RGWRados *store;
58 RGWSyncTraceManager *manager;
59
60 uint64_t interval_msec() override {
61 return cct->_conf->rgw_sync_trace_servicemap_update_interval * 1000;
62 }
63public:
64 RGWSyncTraceServiceMapThread(RGWRados *_store, RGWSyncTraceManager *_manager)
65 : RGWRadosThread(_store, "sync-trace"), store(_store), manager(_manager) {}
66
b3b6e05e 67 int process(const DoutPrefixProvider *dpp) override;
11fdf7f2
TL
68};
69
b3b6e05e 70int RGWSyncTraceServiceMapThread::process(const DoutPrefixProvider *dpp)
11fdf7f2
TL
71{
72 map<string, string> status;
73 status["current_sync"] = manager->get_active_names();
74 int ret = store->update_service_map(std::move(status));
75 if (ret < 0) {
76 ldout(store->ctx(), 0) << "ERROR: update_service_map() returned ret=" << ret << dendl;
77 }
78 return 0;
79}
80
81RGWSyncTraceNodeRef RGWSyncTraceManager::add_node(const RGWSyncTraceNodeRef& parent,
82 const std::string& type,
83 const std::string& id)
84{
85 shunique_lock wl(lock, ceph::acquire_unique);
86 auto handle = alloc_handle();
87 RGWSyncTraceNodeRef& ref = nodes[handle];
88 ref.reset(new RGWSyncTraceNode(cct, handle, parent, type, id));
89 // return a separate shared_ptr that calls finish() on the node instead of
90 // deleting it. the lambda capture holds a reference to the original 'ref'
91 auto deleter = [ref, this] (RGWSyncTraceNode *node) { finish_node(node); };
92 return {ref.get(), deleter};
93}
94
95bool RGWSyncTraceNode::match(const string& search_term, bool search_history)
96{
97 try {
98 std::regex expr(search_term);
99 std::smatch m;
100
101 if (regex_search(prefix, m, expr)) {
102 return true;
103 }
104 if (regex_search(status, m,expr)) {
105 return true;
106 }
107 if (!search_history) {
108 return false;
109 }
110
111 for (auto h : history) {
112 if (regex_search(h, m, expr)) {
113 return true;
114 }
115 }
116 } catch (const std::regex_error& e) {
117 ldout(cct, 5) << "NOTICE: sync trace: bad expression: bad regex search term" << dendl;
118 }
119
120 return false;
121}
122
123void RGWSyncTraceManager::init(RGWRados *store)
124{
125 service_map_thread = new RGWSyncTraceServiceMapThread(store, this);
126 service_map_thread->start();
127}
128
129RGWSyncTraceManager::~RGWSyncTraceManager()
130{
131 cct->get_admin_socket()->unregister_commands(this);
132 service_map_thread->stop();
133 delete service_map_thread;
134
135 nodes.clear();
136}
137
138int RGWSyncTraceManager::hook_to_admin_command()
139{
140 AdminSocket *admin_socket = cct->get_admin_socket();
141
9f95a23c
TL
142 admin_commands = { { "sync trace show name=search,type=CephString,req=false", "sync trace show [filter_str]: show current multisite tracing information" },
143 { "sync trace history name=search,type=CephString,req=false", "sync trace history [filter_str]: show history of multisite tracing information" },
144 { "sync trace active name=search,type=CephString,req=false", "show active multisite sync entities information" },
145 { "sync trace active_short name=search,type=CephString,req=false", "show active multisite sync entities entries" } };
11fdf7f2 146 for (auto cmd : admin_commands) {
9f95a23c
TL
147 int r = admin_socket->register_command(cmd[0], this,
148 cmd[1]);
11fdf7f2
TL
149 if (r < 0) {
150 lderr(cct) << "ERROR: fail to register admin socket command (r=" << r << ")" << dendl;
151 return r;
152 }
153 }
154 return 0;
155}
156
9f95a23c 157static void dump_node(RGWSyncTraceNode *entry, bool show_history, Formatter *f)
11fdf7f2 158{
9f95a23c
TL
159 f->open_object_section("entry");
160 ::encode_json("status", entry->to_str(), f);
11fdf7f2 161 if (show_history) {
9f95a23c 162 f->open_array_section("history");
11fdf7f2 163 for (auto h : entry->get_history()) {
9f95a23c 164 ::encode_json("entry", h, f);
11fdf7f2 165 }
9f95a23c 166 f->close_section();
11fdf7f2 167 }
9f95a23c 168 f->close_section();
11fdf7f2
TL
169}
170
171string RGWSyncTraceManager::get_active_names()
172{
173 shunique_lock rl(lock, ceph::acquire_shared);
174
175 stringstream ss;
176 JSONFormatter f;
177
178 f.open_array_section("result");
179 for (auto n : nodes) {
180 auto& entry = n.second;
181
182 if (!entry->test_flags(RGW_SNS_FLAG_ACTIVE)) {
183 continue;
184 }
185 const string& name = entry->get_resource_name();
186 if (!name.empty()) {
187 ::encode_json("entry", name, &f);
188 }
189 f.flush(ss);
190 }
191 f.close_section();
192 f.flush(ss);
193
194 return ss.str();
195}
196
9f95a23c
TL
197int RGWSyncTraceManager::call(std::string_view command, const cmdmap_t& cmdmap,
198 Formatter *f,
199 std::ostream& ss,
200 bufferlist& out) {
11fdf7f2
TL
201
202 bool show_history = (command == "sync trace history");
203 bool show_short = (command == "sync trace active_short");
204 bool show_active = (command == "sync trace active") || show_short;
205
206 string search;
207
208 auto si = cmdmap.find("search");
209 if (si != cmdmap.end()) {
210 search = boost::get<string>(si->second);
211 }
212
213 shunique_lock rl(lock, ceph::acquire_shared);
214
9f95a23c
TL
215 f->open_object_section("result");
216 f->open_array_section("running");
11fdf7f2
TL
217 for (auto n : nodes) {
218 auto& entry = n.second;
219
220 if (!search.empty() && !entry->match(search, show_history)) {
221 continue;
222 }
223 if (show_active && !entry->test_flags(RGW_SNS_FLAG_ACTIVE)) {
224 continue;
225 }
226 if (show_short) {
227 const string& name = entry->get_resource_name();
228 if (!name.empty()) {
9f95a23c 229 ::encode_json("entry", name, f);
11fdf7f2
TL
230 }
231 } else {
232 dump_node(entry.get(), show_history, f);
233 }
9f95a23c 234 f->flush(out);
11fdf7f2 235 }
9f95a23c 236 f->close_section();
11fdf7f2 237
9f95a23c 238 f->open_array_section("complete");
11fdf7f2
TL
239 for (auto& entry : complete_nodes) {
240 if (!search.empty() && !entry->match(search, show_history)) {
241 continue;
242 }
243 if (show_active && !entry->test_flags(RGW_SNS_FLAG_ACTIVE)) {
244 continue;
245 }
246 dump_node(entry.get(), show_history, f);
9f95a23c 247 f->flush(out);
11fdf7f2 248 }
9f95a23c 249 f->close_section();
11fdf7f2 250
9f95a23c 251 f->close_section();
11fdf7f2 252
9f95a23c 253 return 0;
11fdf7f2
TL
254}
255
256void RGWSyncTraceManager::finish_node(RGWSyncTraceNode *node)
257{
258 RGWSyncTraceNodeRef old_node;
259
260 {
261 shunique_lock wl(lock, ceph::acquire_unique);
262 if (!node) {
263 return;
264 }
265 auto iter = nodes.find(node->handle);
266 if (iter == nodes.end()) {
267 /* not found, already finished */
268 return;
269 }
270
271 if (complete_nodes.full()) {
272 /* take a reference to the entry that is going to be evicted,
273 * can't let it get evicted under lock held, otherwise
274 * it's a deadlock as it will call finish_node()
275 */
276 old_node = complete_nodes.front();
277 }
278
279 complete_nodes.push_back(iter->second);
280 nodes.erase(iter);
281 }
282};
283
284#endif
285