summaryrefslogtreecommitdiff
path: root/ot_stats.c
diff options
context:
space:
mode:
authorerdgeist <>2008-10-24 00:01:42 +0000
committererdgeist <>2008-10-24 00:01:42 +0000
commite89a8aaf58dc18c51d9d249c89e0abb171b033b9 (patch)
tree96ab396a9873cbf839a67cc3f7b4d001d01b6508 /ot_stats.c
parent97980de3d91accef09551718c9fae3a633c13291 (diff)
Move more complicated stats code to its own thread
Diffstat (limited to 'ot_stats.c')
-rw-r--r--ot_stats.c155
1 files changed, 123 insertions, 32 deletions
diff --git a/ot_stats.c b/ot_stats.c
index 8810151..1f5553a 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -11,6 +11,7 @@
11#include <sys/mman.h> 11#include <sys/mman.h>
12#include <stdio.h> 12#include <stdio.h>
13#include <string.h> 13#include <string.h>
14#include <pthread.h>
14 15
15/* Libowfat */ 16/* Libowfat */
16#include "byte.h" 17#include "byte.h"
@@ -19,6 +20,7 @@
19/* Opentracker */ 20/* Opentracker */
20#include "trackerlogic.h" 21#include "trackerlogic.h"
21#include "ot_mutex.h" 22#include "ot_mutex.h"
23#include "ot_iovec.h"
22#include "ot_stats.h" 24#include "ot_stats.h"
23 25
24#ifndef NO_FULLSCRAPE_LOGGING 26#ifndef NO_FULLSCRAPE_LOGGING
@@ -27,6 +29,10 @@
27#define LOG_TO_STDERR( ... ) 29#define LOG_TO_STDERR( ... )
28#endif 30#endif
29 31
32/* Forward declaration */
33static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode );
34#define OT_STATS_TMPSIZE 8192
35
30/* Clumsy counters... to be rethought */ 36/* Clumsy counters... to be rethought */
31static unsigned long long ot_overall_tcp_connections = 0; 37static unsigned long long ot_overall_tcp_connections = 0;
32static unsigned long long ot_overall_udp_connections = 0; 38static unsigned long long ot_overall_udp_connections = 0;
@@ -153,43 +159,43 @@ static char*to_hex(char*d,uint8_t*s){char*m="0123456789ABCDEF";char *t=d;char*e=
153typedef struct { size_t val; ot_torrent * torrent; } ot_record; 159typedef struct { size_t val; ot_torrent * torrent; } ot_record;
154 160
155/* Fetches stats from tracker */ 161/* Fetches stats from tracker */
156size_t stats_top5_txt( char * reply ) { 162size_t stats_top10_txt( char * reply ) {
157 size_t j; 163 size_t j;
158 ot_record top5s[5], top5c[5]; 164 ot_record top10s[10], top10c[10];
159 char *r = reply, hex_out[42]; 165 char *r = reply, hex_out[42];
160 int idx, bucket; 166 int idx, bucket;
161 167
162 byte_zero( top5s, sizeof( top5s ) ); 168 byte_zero( top10s, sizeof( top10s ) );
163 byte_zero( top5c, sizeof( top5c ) ); 169 byte_zero( top10c, sizeof( top10c ) );
164 170
165 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) { 171 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
166 ot_vector *torrents_list = mutex_bucket_lock( bucket ); 172 ot_vector *torrents_list = mutex_bucket_lock( bucket );
167 for( j=0; j<torrents_list->size; ++j ) { 173 for( j=0; j<torrents_list->size; ++j ) {
168 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; 174 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
169 int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx; 175 int idx = 9; while( (idx >= 0) && ( peer_list->peer_count > top10c[idx].val ) ) --idx;
170 if ( idx++ != 4 ) { 176 if ( idx++ != 9 ) {
171 memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); 177 memmove( top10c + idx + 1, top10c + idx, ( 9 - idx ) * sizeof( ot_record ) );
172 top5c[idx].val = peer_list->peer_count; 178 top10c[idx].val = peer_list->peer_count;
173 top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; 179 top10c[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
174 } 180 }
175 idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx; 181 idx = 9; while( (idx >= 0) && ( peer_list->seed_count > top10s[idx].val ) ) --idx;
176 if ( idx++ != 4 ) { 182 if ( idx++ != 9 ) {
177 memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); 183 memmove( top10s + idx + 1, top10s + idx, ( 9 - idx ) * sizeof( ot_record ) );
178 top5s[idx].val = peer_list->seed_count; 184 top10s[idx].val = peer_list->seed_count;
179 top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; 185 top10s[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
180 } 186 }
181 } 187 }
182 mutex_bucket_unlock( bucket ); 188 mutex_bucket_unlock( bucket );
183 } 189 }
184 190
185 r += sprintf( r, "Top5 torrents by peers:\n" ); 191 r += sprintf( r, "Top 10 torrents by peers:\n" );
186 for( idx=0; idx<5; ++idx ) 192 for( idx=0; idx<10; ++idx )
187 if( top5c[idx].torrent ) 193 if( top10c[idx].torrent )
188 r += sprintf( r, "\t%zd\t%s\n", top5c[idx].val, to_hex( hex_out, top5c[idx].torrent->hash) ); 194 r += sprintf( r, "\t%zd\t%s\n", top10c[idx].val, to_hex( hex_out, top10c[idx].torrent->hash) );
189 r += sprintf( r, "Top5 torrents by seeds:\n" ); 195 r += sprintf( r, "Top 10 torrents by seeds:\n" );
190 for( idx=0; idx<5; ++idx ) 196 for( idx=0; idx<10; ++idx )
191 if( top5s[idx].torrent ) 197 if( top10s[idx].torrent )
192 r += sprintf( r, "\t%zd\t%s\n", top5s[idx].val, to_hex( hex_out, top5s[idx].torrent->hash) ); 198 r += sprintf( r, "\t%zd\t%s\n", top10s[idx].val, to_hex( hex_out, top10s[idx].torrent->hash) );
193 199
194 return r - reply; 200 return r - reply;
195} 201}
@@ -284,6 +290,52 @@ bailout_cleanup:
284 return 0; 290 return 0;
285} 291}
286 292
293/*
294 struct {
295 size_t size
296 size_t space
297 size_t count
298 }
299 */
300
301static ssize_t stats_vector_usage( char * reply ) {
302 size_t i, j, *vec_member;
303 char *r = reply;
304 int exactmatch, bucket;
305
306 ot_vector bucketsizes;
307 memset( &bucketsizes, 0, sizeof( bucketsizes ));
308
309 for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
310 ot_vector *torrents_list = mutex_bucket_lock( bucket );
311 for( i=0; i<torrents_list->size; ++i ) {
312 ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list;
313 for( j=0; j<OT_POOLS_COUNT; ++j ) {
314 if( ! ( vec_member = vector_find_or_insert(&bucketsizes, &peer_list->peers[j].size, 3 * sizeof( size_t ), 2 * sizeof(size_t), &exactmatch) ) ) {
315 mutex_bucket_unlock( bucket );
316 return 0;
317 }
318 if( !exactmatch ) {
319 vec_member[0] = peer_list->peers[j].size;
320 vec_member[1] = peer_list->peers[j].space;
321 vec_member[2] = 0;
322 } else
323 ++vec_member[2];
324 }
325 }
326 mutex_bucket_unlock( bucket );
327 }
328
329 for( i = 0; i<bucketsizes.size; ++i ) {
330 r += sprintf( r, "%zd\t%zd\t%zd\n", ((size_t*)bucketsizes.data)[3*i], ((size_t*)bucketsizes.data)[3*i+1], ((size_t*)bucketsizes.data)[3*i+2] );
331 /* Prevent overflow. 8k should be enough for debugging */
332 if( r - reply > OT_STATS_TMPSIZE - 3*10+3 /* 3*%zd + 2*\t + \n */ )
333 break;
334 }
335
336 return r - reply;
337}
338
287static unsigned long events_per_time( unsigned long long events, time_t t ) { 339static unsigned long events_per_time( unsigned long long events, time_t t ) {
288 return events / ( (unsigned int)t ? (unsigned int)t : 1 ); 340 return events / ( (unsigned int)t ? (unsigned int)t : 1 );
289} 341}
@@ -454,7 +506,7 @@ size_t stats_return_tracker_version( char *reply ) {
454 506
455size_t return_stats_for_tracker( char *reply, int mode, int format ) { 507size_t return_stats_for_tracker( char *reply, int mode, int format ) {
456 format = format; 508 format = format;
457 switch( mode ) { 509 switch( mode & TASK_TASK_MASK ) {
458 case TASK_STATS_CONNS: 510 case TASK_STATS_CONNS:
459 return stats_connections_mrtg( reply ); 511 return stats_connections_mrtg( reply );
460 case TASK_STATS_SCRAPE: 512 case TASK_STATS_SCRAPE:
@@ -463,18 +515,10 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
463 return stats_udpconnections_mrtg( reply ); 515 return stats_udpconnections_mrtg( reply );
464 case TASK_STATS_TCP: 516 case TASK_STATS_TCP:
465 return stats_tcpconnections_mrtg( reply ); 517 return stats_tcpconnections_mrtg( reply );
466 case TASK_STATS_PEERS:
467 return stats_peers_mrtg( reply );
468 case TASK_STATS_TORRENTS:
469 return stats_torrents_mrtg( reply );
470 case TASK_STATS_TORADDREM: 518 case TASK_STATS_TORADDREM:
471 return stats_toraddrem_mrtg( reply ); 519 return stats_toraddrem_mrtg( reply );
472 case TASK_STATS_STARTSTOP: 520 case TASK_STATS_STARTSTOP:
473 return stats_startstop_mrtg( reply ); 521 return stats_startstop_mrtg( reply );
474 case TASK_STATS_SLASH24S:
475 return stats_slash24s_txt( reply, 25, 16 );
476 case TASK_STATS_TOP5:
477 return stats_top5_txt( reply );
478 case TASK_STATS_FULLSCRAPE: 522 case TASK_STATS_FULLSCRAPE:
479 return stats_fullscrapes_mrtg( reply ); 523 return stats_fullscrapes_mrtg( reply );
480 case TASK_STATS_HTTPERRORS: 524 case TASK_STATS_HTTPERRORS:
@@ -485,11 +529,36 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
485 case TASK_STATS_BUSY_NETWORKS: 529 case TASK_STATS_BUSY_NETWORKS:
486 return stats_return_busy_networks( reply ); 530 return stats_return_busy_networks( reply );
487#endif 531#endif
532#ifdef _DEBUG_VECTOR
533 case TASK_STATS_VECTOR_DEBUG:
534 return vector_info( reply );
535#endif
488 default: 536 default:
489 return 0; 537 return 0;
490 } 538 }
491} 539}
492 540
541static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) {
542 char *r;
543
544 *iovec_entries = 0;
545 *iovector = NULL;
546 if( !( r = iovec_increase( iovec_entries, iovector, OT_STATS_TMPSIZE ) ) )
547 return;
548
549 switch( mode & TASK_TASK_MASK ) {
550 case TASK_STATS_TORRENTS: r += stats_torrents_mrtg( r ); break;
551 case TASK_STATS_PEERS: r += stats_peers_mrtg( r ); break;
552 case TASK_STATS_SLASH24S: r += stats_slash24s_txt( r, 25, 16 ); break;
553 case TASK_STATS_TOP10: r += stats_top10_txt( r ); break;
554 case TASK_STATS_MEMORY: r += stats_vector_usage( r ); break;
555 default:
556 iovec_free(iovec_entries, iovector);
557 return;
558 }
559 iovec_fixlast( iovec_entries, iovector, r );
560}
561
493void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ) { 562void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ) {
494 switch( event ) { 563 switch( event ) {
495 case EVENT_ACCEPT: 564 case EVENT_ACCEPT:
@@ -537,12 +606,34 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_
537 } 606 }
538} 607}
539 608
609static void * stats_worker( void * args ) {
610 int iovec_entries;
611 struct iovec *iovector;
612
613 args = args;
614
615 while( 1 ) {
616 ot_tasktype tasktype = TASK_STATS;
617 ot_taskid taskid = mutex_workqueue_poptask( &tasktype );
618 stats_make( &iovec_entries, &iovector, tasktype );
619 if( mutex_workqueue_pushresult( taskid, iovec_entries, iovector ) )
620 iovec_free( &iovec_entries, &iovector );
621 }
622 return NULL;
623}
624
625void stats_deliver( int64 socket, int tasktype ) {
626 mutex_workqueue_pushtask( socket, tasktype );
627}
628
629static pthread_t thread_id;
540void stats_init( ) { 630void stats_init( ) {
541 ot_start_time = g_now; 631 ot_start_time = g_now;
632 pthread_create( &thread_id, NULL, stats_worker, NULL );
542} 633}
543 634
544void stats_deinit( ) { 635void stats_deinit( ) {
545 636 pthread_cancel( thread_id );
546} 637}
547 638
548const char *g_version_stats_c = "$Source$: $Revision$\n"; 639const char *g_version_stats_c = "$Source$: $Revision$\n";