diff options
author | erdgeist <> | 2008-10-24 00:01:42 +0000 |
---|---|---|
committer | erdgeist <> | 2008-10-24 00:01:42 +0000 |
commit | e89a8aaf58dc18c51d9d249c89e0abb171b033b9 (patch) | |
tree | 96ab396a9873cbf839a67cc3f7b4d001d01b6508 /ot_stats.c | |
parent | 97980de3d91accef09551718c9fae3a633c13291 (diff) |
Move more complicated stats code to its own thread
Diffstat (limited to 'ot_stats.c')
-rw-r--r-- | ot_stats.c | 155 |
1 files changed, 123 insertions, 32 deletions
@@ -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 */ | ||
33 | static 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 */ |
31 | static unsigned long long ot_overall_tcp_connections = 0; | 37 | static unsigned long long ot_overall_tcp_connections = 0; |
32 | static unsigned long long ot_overall_udp_connections = 0; | 38 | static 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= | |||
153 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; | 159 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; |
154 | 160 | ||
155 | /* Fetches stats from tracker */ | 161 | /* Fetches stats from tracker */ |
156 | size_t stats_top5_txt( char * reply ) { | 162 | size_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 | |||
301 | static 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 | |||
287 | static unsigned long events_per_time( unsigned long long events, time_t t ) { | 339 | static 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 | ||
455 | size_t return_stats_for_tracker( char *reply, int mode, int format ) { | 507 | size_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 | ||
541 | static 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 | |||
493 | void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ) { | 562 | void 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 | ||
609 | static 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 | |||
625 | void stats_deliver( int64 socket, int tasktype ) { | ||
626 | mutex_workqueue_pushtask( socket, tasktype ); | ||
627 | } | ||
628 | |||
629 | static pthread_t thread_id; | ||
540 | void stats_init( ) { | 630 | void 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 | ||
544 | void stats_deinit( ) { | 635 | void stats_deinit( ) { |
545 | 636 | pthread_cancel( thread_id ); | |
546 | } | 637 | } |
547 | 638 | ||
548 | const char *g_version_stats_c = "$Source$: $Revision$\n"; | 639 | const char *g_version_stats_c = "$Source$: $Revision$\n"; |