From: Steinar H. Gunderson Date: Wed, 10 Apr 2013 21:11:00 +0000 (+0200) Subject: Factor statistics writing into its own class and file. X-Git-Tag: 1.0.0~160 X-Git-Url: https://git.sesse.net/?p=cubemap;a=commitdiff_plain;h=e8eff7cedea352b618b114a4d88bb8110d787e4c Factor statistics writing into its own class and file. --- diff --git a/stats.cpp b/stats.cpp new file mode 100644 index 0000000..445bae7 --- /dev/null +++ b/stats.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +#include "serverpool.h" +#include "stats.h" + +using namespace std; + +extern ServerPool *servers; + +StatsThread::StatsThread(const std::string &stats_file, int stats_interval) + : stats_file(stats_file), + stats_interval(stats_interval) +{ +} + +void StatsThread::run() +{ + should_stop = false; + pthread_create(&worker_thread, NULL, do_work_thunk, this); +} + +void StatsThread::stop() +{ + should_stop = true; + pthread_kill(worker_thread, SIGHUP); + if (pthread_join(worker_thread, NULL) == -1) { + perror("pthread_join"); + exit(1); + } +} + +void *StatsThread::do_work_thunk(void *arg) +{ + StatsThread *stats_thread = reinterpret_cast(arg); + stats_thread->do_work(); + return NULL; +} + +void StatsThread::do_work() +{ + while (!should_stop) { + int fd; + FILE *fp; + time_t now; + vector client_stats; + + // Open a new, temporary file. + char *filename = strdup((stats_file + ".new.XXXXXX").c_str()); + fd = mkostemp(filename, O_WRONLY); + if (fd == -1) { + perror(filename); + free(filename); + goto sleep; + } + + fp = fdopen(fd, "w"); + if (fp == NULL) { + perror("fdopen"); + close(fd); + unlink(filename); + free(filename); + goto sleep; + } + + now = time(NULL); + client_stats = servers->get_client_stats(); + for (size_t i = 0; i < client_stats.size(); ++i) { + fprintf(fp, "%s %s %d %llu\n", + client_stats[i].remote_addr.c_str(), + client_stats[i].stream_id.c_str(), + int(now - client_stats[i].connect_time), + (long long unsigned)(client_stats[i].bytes_sent)); + } + if (fclose(fp) == EOF) { + perror("fclose"); + unlink(filename); + free(filename); + goto sleep; + } + + if (rename(filename, stats_file.c_str()) == -1) { + perror("rename"); + unlink(filename); + } + +sleep: + int left_to_sleep = stats_interval; + do { + left_to_sleep = sleep(left_to_sleep); + } while (left_to_sleep > 0 && !should_stop); + } +} diff --git a/stats.h b/stats.h new file mode 100644 index 0000000..c4fb17a --- /dev/null +++ b/stats.h @@ -0,0 +1,29 @@ +#ifndef _STATS_H +#define _STATS_H 1 + +#include +#include + +// A thread that regularly writes out statistics, ie. a list of all connected clients +// with some information about each. + +class StatsThread { +public: + StatsThread(const std::string &stats_file, int stats_interval); + void run(); + void stop(); + +private: + // Recover the this pointer, and call do_work(). + static void *do_work_thunk(void *arg); + + void do_work(); + + std::string stats_file; + int stats_interval; + + pthread_t worker_thread; + volatile bool should_stop; +}; + +#endif // !defined(_STATS_H)