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 | |
| parent | 97980de3d91accef09551718c9fae3a633c13291 (diff) | |
Move more complicated stats code to its own thread
| -rw-r--r-- | ot_stats.c | 155 | ||||
| -rw-r--r-- | ot_stats.h | 1 |
2 files changed, 124 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"; |
| @@ -35,6 +35,7 @@ enum { | |||
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ); | 37 | void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ); |
| 38 | void stats_deliver( int64 socket, int tasktype ); | ||
| 38 | size_t return_stats_for_tracker( char *reply, int mode, int format ); | 39 | size_t return_stats_for_tracker( char *reply, int mode, int format ); |
| 39 | size_t stats_return_tracker_version( char *reply ); | 40 | size_t stats_return_tracker_version( char *reply ); |
| 40 | void stats_init( ); | 41 | void stats_init( ); |
