stats-plugin.c revision 85b14555888acec410734a16561f2d79c626cad9
/* Copyright (c) 2011-2014 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "llist.h"
#include "str.h"
#include "time-util.h"
#include "settings-parser.h"
#include "stats-connection.h"
#include "stats-plugin.h"
#include <sys/resource.h>
#define STATS_CONTEXT(obj) \
/* If session isn't refreshed every 15 minutes, it's dropped.
Must be smaller than MAIL_SESSION_IDLE_TIMEOUT_MSECS in stats server */
#define REFRESH_CHECK_INTERVAL 100
#define MAIL_STATS_SOCKET_NAME "stats-mail"
#define PROC_IO_PATH "/proc/self/io"
#define USECS_PER_SEC 1000000
struct stats_transaction_context {
struct mailbox_transaction_context *trans;
struct mailbox_transaction_stats prev_stats;
};
struct stats_storage {
struct mail_storage_callbacks old_callbacks;
void *old_context;
};
struct stats_mailbox {
union mailbox_module_context module_ctx;
};
const char *stats_plugin_version = DOVECOT_ABI_VERSION;
struct stats_user_module stats_user_module =
static bool proc_io_disabled = FALSE;
static int proc_io_fd = -1;
static unsigned int stats_user_count = 0;
const struct mailbox_transaction_stats *src)
{
}
const struct mailbox_transaction_stats *src)
{
}
struct mailbox_transaction_stats *dest_r)
{
struct stats_transaction_context *strans;
}
static int
{
const char *const *tmp;
return -1;
return -1;
return -1;
return -1;
}
}
return 0;
}
static int process_io_open(void)
{
if (proc_io_fd != -1)
return proc_io_fd;
if (proc_io_disabled)
return -1;
/* kludge: if we're running with permissions temporarily
dropped, get them temporarily back so we can open
if (seteuid(0) == 0) {
/* oops, this is bad */
}
}
}
if (proc_io_fd == -1) {
return -1;
}
return proc_io_fd;
}
{
char buf[1024];
return;
if (ret <= 0) {
if (ret == -1)
else
/* just shouldn't happen.. */
} else {
T_BEGIN {
i_error("Invalid input in file %s",
}
} T_END;
}
}
{
/* cputime */
}
{
if (stats_user_count == 1) {
/* the first user sets the global user. the second user sets
it to NULL. when we get back to one user we'll need to set
the global user again somewhere. do it here. */
/* skip time spent waiting in ioloop */
} else {
}
}
{
long long usecs;
}
}
const struct mail_stats *old_stats,
const struct mail_stats *new_stats)
{
&old_stats->clock_time);
}
{
(unsigned long long)stats->disk_input);
(unsigned long long)stats->disk_output);
(unsigned long long)stats->read_bytes);
(unsigned long long)stats->write_bytes);
}
{
struct mail_stats new_stats;
&new_stats);
}
const struct mail_stats *cur)
{
sizeof(cur->trans_stats)) != 0)
return TRUE;
/* allow a tiny bit of changes that are caused by this
timeout handling */
return TRUE;
return TRUE;
return TRUE;
return TRUE;
changed by stats checking itself */
return FALSE;
}
static bool
bool *changed_r, unsigned int *to_next_secs_r)
{
unsigned int diff;
&suser->session_stats)) {
return TRUE;
}
if (!suser->session_sent_duplicate) {
/* send one duplicate notification so stats reader
knows that this session is idle now */
return TRUE;
}
*to_next_secs_r = 1;
return FALSE;
}
if (diff < SESSION_STATS_FORCE_REFRESH_SECS) {
return FALSE;
}
return TRUE;
}
{
unsigned int to_next_secs;
bool changed;
&suser->session_stats);
}
}
static struct mailbox_transaction_context *
{
struct mailbox_transaction_context *trans;
struct stats_transaction_context *strans;
return trans;
}
struct stats_transaction_context *strans)
{
}
static int
struct mail_transaction_commit_changes *changes_r)
{
}
static void
{
}
{
bool ret;
if (!ret && !*tryagain_r) {
/* end of search */
return FALSE;
}
if (*tryagain_r ||
/* a) retrying, so this is a long running search.
b) we've returned enough matches */
}
return ret;
}
static void
{
/* most importantly we want to refresh stats for very long running
mailbox syncs */
}
{
return;
}
{
struct stats_mailbox *sbox;
return;
}
{
if (stats_global_user != NULL)
}
{
unsigned int last_update_secs;
if (stats_global_user == NULL)
if (stats_global_user != NULL)
}
}
{
i_assert(stats_user_count > 0);
if (--stats_user_count == 0) {
/* we were updating the session lazily. do one final update. */
} else {
}
/* send final stats before disconnection */
}
{
struct ioloop_context *ioloop_ctx =
struct stats_user *suser;
unsigned int refresh_secs;
if (ioloop_ctx == NULL) {
/* we're probably running some test program, or at least
mail-storage-service wasn't used to create this user.
disable stats tracking. */
return;
}
if (user->autocreated) {
/* lda / shared user. we're not tracking this one. */
return;
}
/* get refresh time */
return;
return;
}
if (refresh_secs == 0)
return;
if (global_stats_conn == NULL) {
}
if (stats_user_count == 0) {
/* first user connection */
} else if (stats_user_count == 1) {
/* second user connection. we'll need to start doing
per-io callback tracking now. (we might have been doing it
also previously but just temporarily quickly dropped to
having 1 user, in which case stats_global_user=NULL) */
if (stats_global_user != NULL) {
}
}
v->deinit = stats_user_deinit;
}
static struct mail_storage_hooks stats_mail_storage_hooks = {
};
{
}
void stats_plugin_deinit(void)
{
if (global_stats_conn != NULL)
}