Factor statistics writing into its own class and file.
[cubemap] / stats.cpp
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <signal.h>
6 #include <pthread.h>
7
8 #include "serverpool.h"
9 #include "stats.h"
10
11 using namespace std;
12
13 extern ServerPool *servers;
14
15 StatsThread::StatsThread(const std::string &stats_file, int stats_interval)
16         : stats_file(stats_file),
17           stats_interval(stats_interval)
18 {
19 }
20
21 void StatsThread::run()
22 {
23         should_stop = false;
24         pthread_create(&worker_thread, NULL, do_work_thunk, this);
25 }
26
27 void StatsThread::stop()
28 {
29         should_stop = true;
30         pthread_kill(worker_thread, SIGHUP);
31         if (pthread_join(worker_thread, NULL) == -1) {
32                 perror("pthread_join");
33                 exit(1);
34         }
35 }
36         
37 void *StatsThread::do_work_thunk(void *arg)
38 {
39         StatsThread *stats_thread = reinterpret_cast<StatsThread *>(arg);
40         stats_thread->do_work();
41         return NULL;
42 }
43
44 void StatsThread::do_work()
45 {
46         while (!should_stop) {
47                 int fd;
48                 FILE *fp;
49                 time_t now;
50                 vector<ClientStats> client_stats;
51
52                 // Open a new, temporary file.
53                 char *filename = strdup((stats_file + ".new.XXXXXX").c_str());
54                 fd = mkostemp(filename, O_WRONLY);
55                 if (fd == -1) {
56                         perror(filename);
57                         free(filename);
58                         goto sleep;
59                 }
60
61                 fp = fdopen(fd, "w");
62                 if (fp == NULL) {
63                         perror("fdopen");
64                         close(fd);
65                         unlink(filename);
66                         free(filename);
67                         goto sleep;
68                 }
69
70                 now = time(NULL);
71                 client_stats = servers->get_client_stats();
72                 for (size_t i = 0; i < client_stats.size(); ++i) {
73                         fprintf(fp, "%s %s %d %llu\n",
74                                 client_stats[i].remote_addr.c_str(),
75                                 client_stats[i].stream_id.c_str(),
76                                 int(now - client_stats[i].connect_time),
77                                 (long long unsigned)(client_stats[i].bytes_sent));
78                 }
79                 if (fclose(fp) == EOF) {
80                         perror("fclose");
81                         unlink(filename);
82                         free(filename);
83                         goto sleep;
84                 }
85                 
86                 if (rename(filename, stats_file.c_str()) == -1) {
87                         perror("rename");
88                         unlink(filename);
89                 }
90
91 sleep:
92                 int left_to_sleep = stats_interval;
93                 do {
94                         left_to_sleep = sleep(left_to_sleep);
95                 } while (left_to_sleep > 0 && !should_stop);
96         }
97 }