File: stats.cpp

package info (click to toggle)
cubemap 1.5.2-3
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 908 kB
  • sloc: ansic: 8,411; cpp: 5,730; sh: 114; perl: 112; makefile: 76
file content (143 lines) | stat: -rw-r--r-- 3,880 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <vector>

#include "client.h"
#include "log.h"
#include "serverpool.h"
#include "stats.h"
#include "util.h"

using namespace std;

extern ServerPool *servers;

StatsThread::StatsThread(const string &stats_file, int stats_interval)
	: stats_file(stats_file),
	  stats_interval(stats_interval)
{
}

void StatsThread::do_work()
{
	while (!should_stop()) {
		int fd;
		char *filename;
		FILE *fp;
		timespec now;
		vector<ClientStats> client_stats;
		vector<HLSZombie> hls_zombies;
		unordered_map<string, HLSZombie> remaining_hls_zombies;

		if (clock_gettime(CLOCK_MONOTONIC_COARSE, &now) == -1) {
			log_perror("clock_gettime(CLOCK_MONOTONIC_COARSE)");
			goto sleep;
		}

		// Open a new, temporary file.
		filename = strdup((stats_file + ".new.XXXXXX").c_str());
		fd = mkostemp(filename, O_WRONLY | O_CLOEXEC);
		if (fd == -1) {
			log_perror(filename);
			free(filename);
			goto sleep;
		}

		fp = fdopen(fd, "w");
		if (fp == nullptr) {
			log_perror("fdopen");
			safe_close(fd);
			if (unlink(filename) == -1) {
				log_perror(filename);
			}
			free(filename);
			goto sleep;
		}

		// Get all the HLS zombies and combine them into one map (we resolve conflicts
		// by having an arbitrary element win; in practice, that means the lowest
		// server ID).
		for (HLSZombie &zombie : servers->get_hls_zombies()) {
			const string remote_addr = zombie.remote_addr;
			remaining_hls_zombies[move(remote_addr)] = move(zombie);
		}

		// Remove all zombies whose ID match an already ongoing request.
		// (Normally, this is cleared out already when it starts,
		// but the request could happen on a different server from the zombie,
		// or the zombie could be deserialized.)
		for (const ClientStats &stats : servers->get_client_stats()) {
			if (stats.url != "-") {
				remaining_hls_zombies.erase(stats.hls_zombie_key);
			}
		}

		for (const ClientStats &stats : servers->get_client_stats()) {
			string url = stats.url;
			if (url == "-") {
				// No download going on currently; could it be waiting for more HLS fragments?
				auto it = remaining_hls_zombies.find(stats.remote_addr);
				if (it != remaining_hls_zombies.end()) {
					url = it->second.url;
					remaining_hls_zombies.erase(it);
				}
			}

			fprintf(fp, "%s %d %d %s %d %llu %llu %llu \"%s\" \"%s\"\n",
			        stats.remote_addr.c_str(),
			        stats.sock,
			        0,  // Used to be fwmark.
				url.c_str(),
				int(now.tv_sec - stats.connect_time.tv_sec),  // Rather coarse.
				(long long unsigned)(stats.bytes_sent),
				(long long unsigned)(stats.bytes_lost),
				(long long unsigned)(stats.num_loss_events),
				stats.referer.c_str(),
				stats.user_agent.c_str());
		}
		for (const auto &url_and_zombie : remaining_hls_zombies) {
			const HLSZombie &zombie = url_and_zombie.second;
			fprintf(fp, "%s %d %d %s %d %llu %llu %llu \"%s\" \"%s\"\n",
			        zombie.remote_addr.c_str(),
			        0,  // Fake socket. (The Munin script doesn't like negative numbers.)
			        0,  // Used to be fwmark.
				zombie.url.c_str(),
				0,
				0ULL,
				0ULL,
				0ULL,
				zombie.referer.c_str(),
				zombie.user_agent.c_str());
		}
		if (fclose(fp) == EOF) {
			log_perror("fclose");
			if (unlink(filename) == -1) {
				log_perror(filename);
			}
			free(filename);
			goto sleep;
		}
		
		if (rename(filename, stats_file.c_str()) == -1) {
			log_perror("rename");
			if (unlink(filename) == -1) {
				log_perror(filename);
			}
		}
		free(filename);

sleep:
		// Wait until we are asked to quit, stats_interval timeout,
		// or a spurious signal. (The latter will cause us to write stats
		// too often, but that's okay.)
		timespec timeout_ts;
		timeout_ts.tv_sec = stats_interval;
		timeout_ts.tv_nsec = 0;
		wait_for_wakeup(&timeout_ts);
	}
}