|
@@ -306,6 +306,67 @@ HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
|
|
|
HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
|
|
|
clientmap_entries_eq, 0.6, malloc, realloc, free);
|
|
|
|
|
|
+/** How often do we update our estimate which share of v2 and v3 directory
|
|
|
+ * requests is sent to us? We could as well trigger updates of shares from
|
|
|
+ * network status updates, but that means adding a lot of calls into code
|
|
|
+ * that is independent from geoip stats (and keeping them up-to-date). We
|
|
|
+ * are perfectly fine with an approximation of 15-minute granularity. */
|
|
|
+#define REQUEST_SHARE_INTERVAL (15 * 60)
|
|
|
+
|
|
|
+/** When did we last determine which share of v2 and v3 directory requests
|
|
|
+ * is sent to us? */
|
|
|
+static time_t last_time_determined_shares = 0;
|
|
|
+
|
|
|
+/** Sum of products of v2 shares times the number of seconds for which we
|
|
|
+ * consider these shares as valid. */
|
|
|
+static double v2_share_times_seconds;
|
|
|
+
|
|
|
+/** Sum of products of v3 shares times the number of seconds for which we
|
|
|
+ * consider these shares as valid. */
|
|
|
+static double v3_share_times_seconds;
|
|
|
+
|
|
|
+/** Number of seconds we are determining v2 and v3 shares. */
|
|
|
+static int share_seconds;
|
|
|
+
|
|
|
+/** Try to determine which fraction of v2 and v3 directory requests aimed at
|
|
|
+ * caches will be sent to us at time <b>now</b> and store that value in
|
|
|
+ * order to take a mean value later on. */
|
|
|
+static void
|
|
|
+geoip_determine_shares(time_t now)
|
|
|
+{
|
|
|
+ double v2_share = 0.0, v3_share = 0.0;
|
|
|
+ if (router_get_my_share_of_directory_requests(&v2_share, &v3_share) < 0)
|
|
|
+ return;
|
|
|
+ if (last_time_determined_shares) {
|
|
|
+ v2_share_times_seconds += v2_share *
|
|
|
+ ((double) (now - last_time_determined_shares));
|
|
|
+ v3_share_times_seconds += v3_share *
|
|
|
+ ((double) (now - last_time_determined_shares));
|
|
|
+ share_seconds += now - last_time_determined_shares;
|
|
|
+ }
|
|
|
+ last_time_determined_shares = now;
|
|
|
+}
|
|
|
+
|
|
|
+/** Calculate which fraction of v2 and v3 directory requests aimed at caches
|
|
|
+ * have been sent to us since the last call of this function up to time
|
|
|
+ * <b>now</b>. Set *<b>v2_share_out</b> and *<b>v3_share_out</b> to the
|
|
|
+ * fractions of v2 and v3 protocol shares we expect to have seen. Reset
|
|
|
+ * counters afterwards. Return 0 on success, -1 on failure (e.g. when zero
|
|
|
+ * seconds have passed since the last call).*/
|
|
|
+static int
|
|
|
+geoip_get_mean_shares(time_t now, double *v2_share_out,
|
|
|
+ double *v3_share_out)
|
|
|
+{
|
|
|
+ geoip_determine_shares(now);
|
|
|
+ if (!share_seconds)
|
|
|
+ return -1;
|
|
|
+ *v2_share_out = v2_share_times_seconds / ((double) share_seconds);
|
|
|
+ *v3_share_out = v3_share_times_seconds / ((double) share_seconds);
|
|
|
+ v2_share_times_seconds = v3_share_times_seconds = 0.0;
|
|
|
+ share_seconds = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/** Note that we've seen a client connect from the IP <b>addr</b> (host order)
|
|
|
* at time <b>now</b>. Ignored by all but bridges and directories if
|
|
|
* configured accordingly. */
|
|
@@ -391,6 +452,10 @@ geoip_note_client_seen(geoip_client_action_t action,
|
|
|
else
|
|
|
++country->n_v2_ns_requests[REQUEST_HIST_LEN-1];
|
|
|
}
|
|
|
+
|
|
|
+ /* Periodically determine share of requests that we should see */
|
|
|
+ if (last_time_determined_shares + REQUEST_SHARE_INTERVAL < now)
|
|
|
+ geoip_determine_shares(now);
|
|
|
}
|
|
|
|
|
|
if (!client_history_starts) {
|
|
@@ -646,7 +711,7 @@ dump_geoip_stats(void)
|
|
|
since,
|
|
|
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
|
|
|
goto done;
|
|
|
- if (!router_get_my_share_of_directory_requests(&v2_share, &v3_share)) {
|
|
|
+ if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
|
|
|
if (fprintf(out, "v2-ns-share %0.2lf%%\n", v2_share*100) < 0)
|
|
|
goto done;
|
|
|
if (fprintf(out, "v3-ns-share %0.2lf%%\n", v3_share*100) < 0)
|