1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 John Spray <john.spray@redhat.com>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
14 #include "DaemonState.h"
16 #include <experimental/iterator>
18 #include "MgrSession.h"
19 #include "include/stringify.h"
20 #include "common/Formatter.h"
22 #define dout_context g_ceph_context
23 #define dout_subsys ceph_subsys_mgr
25 #define dout_prefix *_dout << "mgr " << __func__ << " "
31 using std::ostringstream
;
33 using std::stringstream
;
34 using std::unique_ptr
;
36 void DeviceState::set_metadata(map
<string
,string
>&& m
)
38 metadata
= std::move(m
);
39 auto p
= metadata
.find("life_expectancy_min");
40 if (p
!= metadata
.end()) {
41 life_expectancy
.first
.parse(p
->second
);
43 p
= metadata
.find("life_expectancy_max");
44 if (p
!= metadata
.end()) {
45 life_expectancy
.second
.parse(p
->second
);
47 p
= metadata
.find("life_expectancy_stamp");
48 if (p
!= metadata
.end()) {
49 life_expectancy_stamp
.parse(p
->second
);
51 p
= metadata
.find("wear_level");
52 if (p
!= metadata
.end()) {
53 wear_level
= atof(p
->second
.c_str());
57 void DeviceState::set_life_expectancy(utime_t from
, utime_t to
, utime_t now
)
59 life_expectancy
= make_pair(from
, to
);
60 life_expectancy_stamp
= now
;
61 if (from
!= utime_t()) {
62 metadata
["life_expectancy_min"] = stringify(from
);
64 metadata
["life_expectancy_min"] = "";
66 if (to
!= utime_t()) {
67 metadata
["life_expectancy_max"] = stringify(to
);
69 metadata
["life_expectancy_max"] = "";
71 if (now
!= utime_t()) {
72 metadata
["life_expectancy_stamp"] = stringify(now
);
74 metadata
["life_expectancy_stamp"] = "";
78 void DeviceState::rm_life_expectancy()
80 life_expectancy
= make_pair(utime_t(), utime_t());
81 life_expectancy_stamp
= utime_t();
82 metadata
.erase("life_expectancy_min");
83 metadata
.erase("life_expectancy_max");
84 metadata
.erase("life_expectancy_stamp");
87 void DeviceState::set_wear_level(float wear
)
91 metadata
["wear_level"] = stringify(wear
);
93 metadata
.erase("wear_level");
97 string
DeviceState::get_life_expectancy_str(utime_t now
) const
99 if (life_expectancy
.first
== utime_t()) {
102 if (now
>= life_expectancy
.first
) {
105 utime_t min
= life_expectancy
.first
- now
;
106 utime_t max
= life_expectancy
.second
- now
;
107 if (life_expectancy
.second
== utime_t()) {
108 return string(">") + timespan_str(make_timespan(min
));
110 string a
= timespan_str(make_timespan(min
));
111 string b
= timespan_str(make_timespan(max
));
115 return a
+ " to " + b
;
118 void DeviceState::dump(Formatter
*f
) const
120 f
->dump_string("devid", devid
);
121 f
->open_array_section("location");
122 for (auto& i
: attachments
) {
123 f
->open_object_section("attachment");
124 f
->dump_string("host", std::get
<0>(i
));
125 f
->dump_string("dev", std::get
<1>(i
));
126 f
->dump_string("path", std::get
<2>(i
));
130 f
->open_array_section("daemons");
131 for (auto& i
: daemons
) {
132 f
->dump_stream("daemon") << i
;
135 if (life_expectancy
.first
!= utime_t()) {
136 f
->dump_stream("life_expectancy_min") << life_expectancy
.first
;
137 f
->dump_stream("life_expectancy_max") << life_expectancy
.second
;
138 f
->dump_stream("life_expectancy_stamp")
139 << life_expectancy_stamp
;
141 if (wear_level
>= 0) {
142 f
->dump_float("wear_level", wear_level
);
146 void DeviceState::print(ostream
& out
) const
148 out
<< "device " << devid
<< "\n";
149 for (auto& i
: attachments
) {
150 out
<< "attachment " << std::get
<0>(i
) << " " << std::get
<1>(i
) << " "
151 << std::get
<2>(i
) << "\n";
154 std::copy(std::begin(daemons
), std::end(daemons
),
155 std::experimental::make_ostream_joiner(out
, ","));
157 if (life_expectancy
.first
!= utime_t()) {
158 out
<< "life_expectancy " << life_expectancy
.first
<< " to "
159 << life_expectancy
.second
160 << " (as of " << life_expectancy_stamp
<< ")\n";
162 if (wear_level
>= 0) {
163 out
<< "wear_level " << wear_level
<< "\n";
167 void DaemonState::set_metadata(const std::map
<std::string
,std::string
>& m
)
170 devices_bypath
.clear();
172 if (auto found
= m
.find("device_ids"); found
!= m
.end()) {
173 auto& device_ids
= found
->second
;
174 std::map
<std::string
,std::string
> paths
; // devname -> id or path
175 if (auto found
= m
.find("device_paths"); found
!= m
.end()) {
176 get_str_map(found
->second
, &paths
, ",; ");
180 [&paths
, this](std::string_view devname
, std::string_view id
) {
186 devices
.emplace(id
, devname
);
187 if (auto path
= paths
.find(std::string(id
)); path
!= paths
.end()) {
189 devices_bypath
.emplace(id
, path
->second
);
193 if (auto found
= m
.find("hostname"); found
!= m
.end()) {
194 hostname
= found
->second
;
198 const std::map
<std::string
,std::string
>& DaemonState::_get_config_defaults()
200 if (config_defaults
.empty() &&
201 config_defaults_bl
.length()) {
202 auto p
= config_defaults_bl
.cbegin();
204 decode(config_defaults
, p
);
205 } catch (buffer::error
& e
) {
208 return config_defaults
;
211 void DaemonStateIndex::insert(DaemonStatePtr dm
)
213 std::unique_lock l
{lock
};
217 void DaemonStateIndex::_insert(DaemonStatePtr dm
)
219 if (all
.count(dm
->key
)) {
223 by_server
[dm
->hostname
][dm
->key
] = dm
;
226 for (auto& i
: dm
->devices
) {
227 auto d
= _get_or_create_device(i
.first
);
228 d
->daemons
.insert(dm
->key
);
229 auto p
= dm
->devices_bypath
.find(i
.first
);
230 if (p
!= dm
->devices_bypath
.end()) {
231 d
->attachments
.insert(std::make_tuple(dm
->hostname
, i
.second
, p
->second
));
233 d
->attachments
.insert(std::make_tuple(dm
->hostname
, i
.second
,
239 void DaemonStateIndex::_erase(const DaemonKey
& dmk
)
241 ceph_assert(ceph_mutex_is_wlocked(lock
));
243 const auto to_erase
= all
.find(dmk
);
244 ceph_assert(to_erase
!= all
.end());
245 const auto dm
= to_erase
->second
;
247 for (auto& i
: dm
->devices
) {
248 auto d
= _get_or_create_device(i
.first
);
249 ceph_assert(d
->daemons
.count(dmk
));
250 d
->daemons
.erase(dmk
);
251 auto p
= dm
->devices_bypath
.find(i
.first
);
252 if (p
!= dm
->devices_bypath
.end()) {
253 d
->attachments
.erase(make_tuple(dm
->hostname
, i
.second
, p
->second
));
255 d
->attachments
.erase(make_tuple(dm
->hostname
, i
.second
, std::string()));
262 auto &server_collection
= by_server
[dm
->hostname
];
263 server_collection
.erase(dm
->key
);
264 if (server_collection
.empty()) {
265 by_server
.erase(dm
->hostname
);
271 DaemonStateCollection
DaemonStateIndex::get_by_service(
272 const std::string
& svc
) const
274 std::shared_lock l
{lock
};
276 DaemonStateCollection result
;
278 for (const auto& [key
, state
] : all
) {
279 if (key
.type
== svc
) {
287 DaemonStateCollection
DaemonStateIndex::get_by_server(
288 const std::string
&hostname
) const
290 std::shared_lock l
{lock
};
292 if (auto found
= by_server
.find(hostname
); found
!= by_server
.end()) {
293 return found
->second
;
299 bool DaemonStateIndex::exists(const DaemonKey
&key
) const
301 std::shared_lock l
{lock
};
303 return all
.count(key
) > 0;
306 DaemonStatePtr
DaemonStateIndex::get(const DaemonKey
&key
)
308 std::shared_lock l
{lock
};
310 auto iter
= all
.find(key
);
311 if (iter
!= all
.end()) {
318 void DaemonStateIndex::rm(const DaemonKey
&key
)
320 std::unique_lock l
{lock
};
324 void DaemonStateIndex::_rm(const DaemonKey
&key
)
326 if (all
.count(key
)) {
331 void DaemonStateIndex::cull(const std::string
& svc_name
,
332 const std::set
<std::string
>& names_exist
)
334 std::vector
<string
> victims
;
336 std::unique_lock l
{lock
};
337 auto begin
= all
.lower_bound({svc_name
, ""});
338 auto end
= all
.end();
339 for (auto &i
= begin
; i
!= end
; ++i
) {
340 const auto& daemon_key
= i
->first
;
341 if (daemon_key
.type
!= svc_name
)
343 if (names_exist
.count(daemon_key
.name
) == 0) {
344 victims
.push_back(daemon_key
.name
);
348 for (auto &i
: victims
) {
349 DaemonKey daemon_key
{svc_name
, i
};
350 dout(4) << "Removing data for " << daemon_key
<< dendl
;
355 void DaemonStateIndex::cull_services(const std::set
<std::string
>& types_exist
)
357 std::set
<DaemonKey
> victims
;
359 std::unique_lock l
{lock
};
360 for (auto it
= all
.begin(); it
!= all
.end(); ++it
) {
361 const auto& daemon_key
= it
->first
;
362 if (it
->second
->service_daemon
&&
363 types_exist
.count(daemon_key
.type
) == 0) {
364 victims
.insert(daemon_key
);
368 for (auto &i
: victims
) {
369 dout(4) << "Removing data for " << i
<< dendl
;
374 void DaemonPerfCounters::update(const MMgrReport
& report
)
376 dout(20) << "loading " << report
.declare_types
.size() << " new types, "
377 << report
.undeclare_types
.size() << " old types, had "
378 << types
.size() << " types, got "
379 << report
.packed
.length() << " bytes of data" << dendl
;
381 // Retrieve session state
382 auto priv
= report
.get_connection()->get_priv();
383 auto session
= static_cast<MgrSession
*>(priv
.get());
385 // Load any newly declared types
386 for (const auto &t
: report
.declare_types
) {
387 types
.insert(std::make_pair(t
.path
, t
));
388 session
->declared_types
.insert(t
.path
);
390 // Remove any old types
391 for (const auto &t
: report
.undeclare_types
) {
392 session
->declared_types
.erase(t
);
395 const auto now
= ceph_clock_now();
397 // Parse packed data according to declared set of types
398 auto p
= report
.packed
.cbegin();
400 for (const auto &t_path
: session
->declared_types
) {
401 const auto &t
= types
.at(t_path
);
402 auto instances_it
= instances
.find(t_path
);
403 // Always check the instance exists, as we don't prevent yet
404 // multiple sessions from daemons with the same name, and one
405 // session clearing stats created by another on open.
406 if (instances_it
== instances
.end()) {
407 instances_it
= instances
.insert({t_path
, t
.type
}).first
;
410 uint64_t avgcount
= 0;
411 uint64_t avgcount2
= 0;
414 if (t
.type
& PERFCOUNTER_LONGRUNAVG
) {
416 decode(avgcount2
, p
);
417 instances_it
->second
.push_avg(now
, val
, avgcount
);
419 instances_it
->second
.push(now
, val
);
425 void PerfCounterInstance::push(utime_t t
, uint64_t const &v
)
427 buffer
.push_back({t
, v
});
430 void PerfCounterInstance::push_avg(utime_t t
, uint64_t const &s
,
433 avg_buffer
.push_back({t
, s
, c
});