MXS-1775 Add functions for checking disk space of servers

This commit is contained in:
Johan Wikman
2018-06-05 10:54:15 +03:00
parent 4325ab620b
commit 5172c43e29
4 changed files with 173 additions and 2 deletions

View File

@ -1284,7 +1284,8 @@ how full the corresponding disk may be, before action is taken. E.g. an entry li
specifies that the disk that has been mounted on `/data` may be used until 80% specifies that the disk that has been mounted on `/data` may be used until 80%
of the total space has been consumed. Multiple entries can be specified by of the total space has been consumed. Multiple entries can be specified by
separating them by a comma. If the path is specified using `*`, then the limit separating them by a comma. If the path is specified using `*`, then the limit
applies to all disks. applies to all disks. However, the value of `*` is only applied if there is not
an exact match.
Note that if a particular disk has been mounted on several paths, only one path Note that if a particular disk has been mounted on several paths, only one path
need to be specified. If several are specified, then the one with the smallest need to be specified. If several are specified, then the one with the smallest
@ -1294,8 +1295,12 @@ Examples:
``` ```
disk_space_threshold=*:80 disk_space_threshold=*:80
disk_space_threshold=/data:80 disk_space_threshold=/data:80
disk_space_threshold=/data1:80,/data2:70,/data3:30 disk_space_threshold=/data1:80,/data2:60,*:90
``` ```
The last line means that the disk mounted at `/data1` may be used up to
80%, the disk mounted at `/data2` may be used up to 60% and all other disks
mounted at any paths may be used up until 90% of maximum capacity, before
MaxScale starts to warn to take action.
Note that the path to be used, is one of the paths returned by: Note that the path to be used, is one of the paths returned by:
``` ```

View File

@ -230,6 +230,7 @@ typedef struct monitored_server
uint64_t mon_prev_status; /**< Status before starting the current monitor loop */ uint64_t mon_prev_status; /**< Status before starting the current monitor loop */
uint64_t pending_status; /**< Status during current monitor loop */ uint64_t pending_status; /**< Status during current monitor loop */
bool new_event; /**< Whether an action was taken on the last event */ bool new_event; /**< Whether an action was taken on the last event */
int64_t disk_space_checked; /**< When was the disk space checked the last time */
struct monitored_server *next; /**< The next server in the list */ struct monitored_server *next; /**< The next server in the list */
} MXS_MONITORED_SERVER; } MXS_MONITORED_SERVER;

View File

@ -113,6 +113,12 @@ protected:
return atomic_load_int32(&m_shutdown) != 0; return atomic_load_int32(&m_shutdown) != 0;
} }
bool should_check_disk_space(const MXS_MONITORED_SERVER* pMonitored_server) const;
void check_disk_space(MXS_MONITORED_SERVER* pMonitored_server);
static int64_t get_time_ms();
/** /**
* @brief Configure the monitor. * @brief Configure the monitor.
* *

View File

@ -31,6 +31,7 @@
#include <maxscale/clock.h> #include <maxscale/clock.h>
#include <maxscale/json_api.h> #include <maxscale/json_api.h>
#include <maxscale/log_manager.h> #include <maxscale/log_manager.h>
#include <maxscale/mariadb.hh>
#include <maxscale/mysql_utils.h> #include <maxscale/mysql_utils.h>
#include <maxscale/paths.h> #include <maxscale/paths.h>
#include <maxscale/pcre2.h> #include <maxscale/pcre2.h>
@ -2652,6 +2653,159 @@ bool MonitorInstance::start(const MXS_CONFIG_PARAMETER* pParams)
return started; return started;
} }
//static
int64_t MonitorInstance::get_time_ms()
{
timespec t;
ss_debug(int rv = )clock_gettime(CLOCK_MONOTONIC_COARSE, &t);
ss_dassert(rv == 0);
return t.tv_sec * 1000 + (t.tv_nsec / 1000000);
}
bool MonitorInstance::should_check_disk_space(const MXS_MONITORED_SERVER* pMs) const
{
bool should_check = false;
if (m_monitor->disk_space_check_interval &&
(m_monitor->disk_space_threshold || pMs->server->disk_space_threshold) &&
(pMs->disk_space_checked != -1)) // -1 means disabled
{
int64_t now = get_time_ms();
if (now - pMs->disk_space_checked > m_monitor->disk_space_check_interval)
{
should_check = true;
}
}
return should_check;
}
namespace
{
bool check_disk_space_exhausted(MXS_MONITORED_SERVER* pMs,
const std::string& path,
const maxscale::disk::SizesAndName& san,
int32_t max_percentage)
{
bool disk_space_exhausted = false;
int32_t used_percentage = ((san.total() - san.available()) / (double)san.total()) * 100;
if (used_percentage >= max_percentage)
{
MXS_ERROR("Disk space on %s at %s is exhausted; %d%% of the the disk "
"mounted on the path %s has been used, and the limit it %d%%.",
pMs->server->name, pMs->server->address,
used_percentage, path.c_str(), max_percentage);
disk_space_exhausted = true;
}
return disk_space_exhausted;
}
}
void MonitorInstance::check_disk_space(MXS_MONITORED_SERVER* pMs)
{
std::map<std::string, disk::SizesAndName> info;
int rv = disk::get_info_by_path(pMs->con, &info);
if (rv == 0)
{
bool disk_space_exhausted = false;
MxsDiskSpaceThreshold* pDst =
pMs->server->disk_space_threshold ?
pMs->server->disk_space_threshold : m_monitor->disk_space_threshold;
ss_dassert(pDst);
int32_t star_max_percentage = -1;
std::set<std::string> checked_paths;
for (auto i = pDst->begin(); i != pDst->end(); ++i)
{
string path = i->first;
int32_t max_percentage = i->second;
if (path == "*")
{
star_max_percentage = max_percentage;
}
else
{
auto j = info.find(path);
if (j != info.end())
{
const disk::SizesAndName& san = j->second;
disk_space_exhausted = check_disk_space_exhausted(pMs, path, san, max_percentage);
checked_paths.insert(path);
}
else
{
MXS_WARNING("Disk space threshold specified for %s even though server %s at %s"
"does not have that.",
path.c_str(), pMs->server->name, pMs->server->address);
}
}
}
if (star_max_percentage != -1)
{
for (auto j = info.begin(); j != info.end(); ++j)
{
string path = j->first;
if (checked_paths.find(path) == checked_paths.end())
{
const disk::SizesAndName& san = j->second;
disk_space_exhausted = check_disk_space_exhausted(pMs, path, san, star_max_percentage);
}
}
}
if (disk_space_exhausted)
{
pMs->pending_status |= SERVER_DISK_SPACE_EXHAUSTED;
}
else
{
pMs->pending_status &= ~SERVER_DISK_SPACE_EXHAUSTED;
}
pMs->disk_space_checked = get_time_ms();
}
else
{
SERVER* pServer = pMs->server;
if (mysql_errno(pMs->con) == ER_UNKNOWN_TABLE)
{
// Disable disk space checking for this server.
pMs->disk_space_checked = -1;
MXS_ERROR("Disk space cannot be checked for %s at %s, because either the "
"version %s is too old, or the DISKS information schema plugin "
"has not been installed. Disk space checking has been disabled.",
pServer->name, pServer->address, pServer->version_string);
}
else
{
MXS_ERROR("Checking the disk space for %s at %s failed due to: (%d) %s",
pServer->name, pServer->address,
mysql_errno(pMs->con), mysql_error(pMs->con));
}
}
}
bool MonitorInstance::configure(const MXS_CONFIG_PARAMETER* pParams) bool MonitorInstance::configure(const MXS_CONFIG_PARAMETER* pParams)
{ {
return true; return true;
@ -2689,6 +2843,11 @@ void MonitorInstance::tick()
monitor_clear_pending_status(pMs, SERVER_AUTH_ERROR); monitor_clear_pending_status(pMs, SERVER_AUTH_ERROR);
monitor_set_pending_status(pMs, SERVER_RUNNING); monitor_set_pending_status(pMs, SERVER_RUNNING);
if (should_check_disk_space(pMs))
{
check_disk_space(pMs);
}
update_server_status(pMs); update_server_status(pMs);
} }
else else