/*
This file is part of GNUnet.
Copyright (C) 2009, 2010, 2012, 2014, 2016 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/**
* @file statistics/gnunet-service-statistics.c
* @brief program that tracks statistics
* @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_bio_lib.h"
#include "gnunet_container_lib.h"
#include "gnunet_disk_lib.h"
#include "gnunet_getopt_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_service_lib.h"
#include "gnunet_statistics_service.h"
#include "gnunet_strings_lib.h"
#include "gnunet_time_lib.h"
#include "statistics.h"
/**
* Watch entry.
*/
struct WatchEntry
{
/**
* Watch entries are kept in a linked list.
*/
struct WatchEntry *next;
/**
* Watch entries are kept in a linked list.
*/
struct WatchEntry *prev;
/**
* For which client is this watch entry?
*/
struct ClientEntry *ce;
/**
* Last value we communicated to the client for this watch entry.
*/
uint64_t last_value;
/**
* Unique watch number for this client and this watched value.
*/
uint32_t wid;
/**
* Is last_value valid
* #GNUNET_NO : last_value is n/a, #GNUNET_YES: last_value is valid
*/
int last_value_set;
};
/**
* We keep the statistics organized by subsystem for faster
* lookup during SET operations.
*/
struct SubsystemEntry;
/**
* Entry in the statistics list.
*/
struct StatsEntry
{
/**
* This is a linked list.
*/
struct StatsEntry *next;
/**
* This is a linked list.
*/
struct StatsEntry *prev;
/**
* Subsystem this entry belongs to.
*/
struct SubsystemEntry *subsystem;
/**
* Name for the value stored by this entry, allocated at the end of
* this struct.
*/
const char *name;
/**
* Watch context for changes to this value, or NULL for none.
*/
struct WatchEntry *we_head;
/**
* Watch context for changes to this value, or NULL for none.
*/
struct WatchEntry *we_tail;
/**
* Our value.
*/
uint64_t value;
/**
* Unique ID.
*/
uint32_t uid;
/**
* Is this value persistent?
*/
int persistent;
/**
* Is this value set?
* #GNUNET_NO: value is n/a, #GNUNET_YES: value is valid
*/
int set;
};
/**
* We keep the statistics organized by subsystem for faster
* lookup during SET operations.
*/
struct SubsystemEntry
{
/**
* Subsystems are kept in a DLL.
*/
struct SubsystemEntry *next;
/**
* Subsystems are kept in a DLL.
*/
struct SubsystemEntry *prev;
/**
* Head of list of values kept for this subsystem.
*/
struct StatsEntry *stat_head;
/**
* Tail of list of values kept for this subsystem.
*/
struct StatsEntry *stat_tail;
/**
* Name of the subsystem this entry is for, allocated at
* the end of this struct, do not free().
*/
const char *service;
};
/**
* Client entry.
*/
struct ClientEntry
{
/**
* Corresponding server handle.
*/
struct GNUNET_SERVICE_Client *client;
/**
* Corresponding message queue.
*/
struct GNUNET_MQ_Handle *mq;
/**
* Which subsystem is this client writing to (SET/UPDATE)?
*/
struct SubsystemEntry *subsystem;
/**
* Maximum watch ID used by this client so far.
*/
uint32_t max_wid;
};
/**
* Our configuration.
*/
static const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Head of linked list of subsystems with active statistics.
*/
static struct SubsystemEntry *sub_head;
/**
* Tail of linked list of subsystems with active statistics.
*/
static struct SubsystemEntry *sub_tail;
/**
* Number of connected clients.
*/
static unsigned int client_count;
/**
* Our notification context.
*/
static struct GNUNET_NotificationContext *nc;
/**
* Counter used to generate unique values.
*/
static uint32_t uidgen;
/**
* Set to #GNUNET_YES if we are shutting down as soon as possible.
*/
static int in_shutdown;
/**
* Write persistent statistics to disk.
*/
static void
save ()
{
struct SubsystemEntry *se;
struct StatsEntry *pos;
char *fn;
struct GNUNET_BIO_WriteHandle *wh;
uint16_t size;
unsigned long long total;
size_t