mirror of
				git://erdgeist.org/opentracker
				synced 2025-11-04 03:43:23 +08:00 
			
		
		
		
	Move more complicated stats code to its own thread
This commit is contained in:
		
							parent
							
								
									97980de3d9
								
							
						
					
					
						commit
						e89a8aaf58
					
				
							
								
								
									
										155
									
								
								ot_stats.c
									
									
									
									
									
								
							
							
						
						
									
										155
									
								
								ot_stats.c
									
									
									
									
									
								
							@ -11,6 +11,7 @@
 | 
				
			|||||||
#include <sys/mman.h>
 | 
					#include <sys/mman.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Libowfat */
 | 
					/* Libowfat */
 | 
				
			||||||
#include "byte.h"
 | 
					#include "byte.h"
 | 
				
			||||||
@ -19,6 +20,7 @@
 | 
				
			|||||||
/* Opentracker */
 | 
					/* Opentracker */
 | 
				
			||||||
#include "trackerlogic.h"
 | 
					#include "trackerlogic.h"
 | 
				
			||||||
#include "ot_mutex.h"
 | 
					#include "ot_mutex.h"
 | 
				
			||||||
 | 
					#include "ot_iovec.h"
 | 
				
			||||||
#include "ot_stats.h"
 | 
					#include "ot_stats.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef NO_FULLSCRAPE_LOGGING
 | 
					#ifndef NO_FULLSCRAPE_LOGGING
 | 
				
			||||||
@ -27,6 +29,10 @@
 | 
				
			|||||||
#define LOG_TO_STDERR( ... )
 | 
					#define LOG_TO_STDERR( ... )
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Forward declaration */
 | 
				
			||||||
 | 
					static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode );
 | 
				
			||||||
 | 
					#define OT_STATS_TMPSIZE 8192
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Clumsy counters... to be rethought */
 | 
					/* Clumsy counters... to be rethought */
 | 
				
			||||||
static unsigned long long ot_overall_tcp_connections = 0;
 | 
					static unsigned long long ot_overall_tcp_connections = 0;
 | 
				
			||||||
static unsigned long long ot_overall_udp_connections = 0;
 | 
					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=
 | 
				
			|||||||
typedef struct { size_t val; ot_torrent * torrent; } ot_record;
 | 
					typedef struct { size_t val; ot_torrent * torrent; } ot_record;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Fetches stats from tracker */
 | 
					/* Fetches stats from tracker */
 | 
				
			||||||
size_t stats_top5_txt( char * reply ) {
 | 
					size_t stats_top10_txt( char * reply ) {
 | 
				
			||||||
  size_t    j;
 | 
					  size_t    j;
 | 
				
			||||||
  ot_record top5s[5], top5c[5];
 | 
					  ot_record top10s[10], top10c[10];
 | 
				
			||||||
  char     *r  = reply, hex_out[42];
 | 
					  char     *r  = reply, hex_out[42];
 | 
				
			||||||
  int       idx, bucket;
 | 
					  int       idx, bucket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  byte_zero( top5s, sizeof( top5s ) );
 | 
					  byte_zero( top10s, sizeof( top10s ) );
 | 
				
			||||||
  byte_zero( top5c, sizeof( top5c ) );
 | 
					  byte_zero( top10c, sizeof( top10c ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
 | 
					  for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
 | 
				
			||||||
    ot_vector *torrents_list = mutex_bucket_lock( bucket );
 | 
					    ot_vector *torrents_list = mutex_bucket_lock( bucket );
 | 
				
			||||||
    for( j=0; j<torrents_list->size; ++j ) {
 | 
					    for( j=0; j<torrents_list->size; ++j ) {
 | 
				
			||||||
      ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
 | 
					      ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list;
 | 
				
			||||||
      int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx;
 | 
					      int idx = 9; while( (idx >= 0) && ( peer_list->peer_count > top10c[idx].val ) ) --idx;
 | 
				
			||||||
      if ( idx++ != 4 ) {
 | 
					      if ( idx++ != 9 ) {
 | 
				
			||||||
        memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) );
 | 
					        memmove( top10c + idx + 1, top10c + idx, ( 9 - idx ) * sizeof( ot_record ) );
 | 
				
			||||||
        top5c[idx].val = peer_list->peer_count;
 | 
					        top10c[idx].val = peer_list->peer_count;
 | 
				
			||||||
        top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
 | 
					        top10c[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx;
 | 
					      idx = 9; while( (idx >= 0) && ( peer_list->seed_count > top10s[idx].val ) ) --idx;
 | 
				
			||||||
      if ( idx++ != 4 ) {
 | 
					      if ( idx++ != 9 ) {
 | 
				
			||||||
        memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) );
 | 
					        memmove( top10s + idx + 1, top10s + idx, ( 9 - idx ) * sizeof( ot_record ) );
 | 
				
			||||||
        top5s[idx].val = peer_list->seed_count;
 | 
					        top10s[idx].val = peer_list->seed_count;
 | 
				
			||||||
        top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
 | 
					        top10s[idx].torrent = (ot_torrent*)(torrents_list->data) + j;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    mutex_bucket_unlock( bucket );
 | 
					    mutex_bucket_unlock( bucket );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  r += sprintf( r, "Top5 torrents by peers:\n" );
 | 
					  r += sprintf( r, "Top 10 torrents by peers:\n" );
 | 
				
			||||||
  for( idx=0; idx<5; ++idx )
 | 
					  for( idx=0; idx<10; ++idx )
 | 
				
			||||||
    if( top5c[idx].torrent )
 | 
					    if( top10c[idx].torrent )
 | 
				
			||||||
      r += sprintf( r, "\t%zd\t%s\n", top5c[idx].val, to_hex( hex_out, top5c[idx].torrent->hash) );
 | 
					      r += sprintf( r, "\t%zd\t%s\n", top10c[idx].val, to_hex( hex_out, top10c[idx].torrent->hash) );
 | 
				
			||||||
  r += sprintf( r, "Top5 torrents by seeds:\n" );
 | 
					  r += sprintf( r, "Top 10 torrents by seeds:\n" );
 | 
				
			||||||
  for( idx=0; idx<5; ++idx )
 | 
					  for( idx=0; idx<10; ++idx )
 | 
				
			||||||
    if( top5s[idx].torrent )
 | 
					    if( top10s[idx].torrent )
 | 
				
			||||||
      r += sprintf( r, "\t%zd\t%s\n", top5s[idx].val, to_hex( hex_out, top5s[idx].torrent->hash) );
 | 
					      r += sprintf( r, "\t%zd\t%s\n", top10s[idx].val, to_hex( hex_out, top10s[idx].torrent->hash) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return r - reply;
 | 
					  return r - reply;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -284,6 +290,52 @@ bailout_cleanup:
 | 
				
			|||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 struct {
 | 
				
			||||||
 | 
					   size_t size
 | 
				
			||||||
 | 
					   size_t space
 | 
				
			||||||
 | 
					   size_t count
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t stats_vector_usage( char * reply ) {
 | 
				
			||||||
 | 
					  size_t i, j, *vec_member;
 | 
				
			||||||
 | 
					  char *r = reply;
 | 
				
			||||||
 | 
					  int exactmatch, bucket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ot_vector bucketsizes;
 | 
				
			||||||
 | 
					  memset( &bucketsizes, 0, sizeof( bucketsizes ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for( bucket=0; bucket<OT_BUCKET_COUNT; ++bucket ) {
 | 
				
			||||||
 | 
					    ot_vector *torrents_list = mutex_bucket_lock( bucket );
 | 
				
			||||||
 | 
					    for( i=0; i<torrents_list->size; ++i ) {
 | 
				
			||||||
 | 
					      ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[i] ).peer_list;
 | 
				
			||||||
 | 
					      for( j=0; j<OT_POOLS_COUNT; ++j ) {
 | 
				
			||||||
 | 
					        if( ! ( vec_member = vector_find_or_insert(&bucketsizes, &peer_list->peers[j].size, 3 * sizeof( size_t ), 2 * sizeof(size_t), &exactmatch) ) ) {
 | 
				
			||||||
 | 
					          mutex_bucket_unlock( bucket );
 | 
				
			||||||
 | 
					          return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if( !exactmatch ) {
 | 
				
			||||||
 | 
					          vec_member[0] = peer_list->peers[j].size;          
 | 
				
			||||||
 | 
					          vec_member[1] = peer_list->peers[j].space;          
 | 
				
			||||||
 | 
					          vec_member[2] = 0;          
 | 
				
			||||||
 | 
					        } else
 | 
				
			||||||
 | 
					          ++vec_member[2];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mutex_bucket_unlock( bucket );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for( i = 0; i<bucketsizes.size; ++i ) {
 | 
				
			||||||
 | 
					    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] );
 | 
				
			||||||
 | 
					    /* Prevent overflow. 8k should be enough for debugging */
 | 
				
			||||||
 | 
					    if( r - reply > OT_STATS_TMPSIZE - 3*10+3 /* 3*%zd + 2*\t + \n */ )
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return r - reply;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned long events_per_time( unsigned long long events, time_t t ) {
 | 
					static unsigned long events_per_time( unsigned long long events, time_t t ) {
 | 
				
			||||||
  return events / ( (unsigned int)t ? (unsigned int)t : 1 );
 | 
					  return events / ( (unsigned int)t ? (unsigned int)t : 1 );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -454,7 +506,7 @@ size_t stats_return_tracker_version( char *reply ) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
size_t return_stats_for_tracker( char *reply, int mode, int format ) {
 | 
					size_t return_stats_for_tracker( char *reply, int mode, int format ) {
 | 
				
			||||||
  format = format;
 | 
					  format = format;
 | 
				
			||||||
  switch( mode ) {
 | 
					  switch( mode & TASK_TASK_MASK ) {
 | 
				
			||||||
    case TASK_STATS_CONNS:
 | 
					    case TASK_STATS_CONNS:
 | 
				
			||||||
      return stats_connections_mrtg( reply );
 | 
					      return stats_connections_mrtg( reply );
 | 
				
			||||||
    case TASK_STATS_SCRAPE:
 | 
					    case TASK_STATS_SCRAPE:
 | 
				
			||||||
@ -463,18 +515,10 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
 | 
				
			|||||||
      return stats_udpconnections_mrtg( reply );
 | 
					      return stats_udpconnections_mrtg( reply );
 | 
				
			||||||
    case TASK_STATS_TCP:
 | 
					    case TASK_STATS_TCP:
 | 
				
			||||||
      return stats_tcpconnections_mrtg( reply );
 | 
					      return stats_tcpconnections_mrtg( reply );
 | 
				
			||||||
    case TASK_STATS_PEERS:
 | 
					 | 
				
			||||||
      return stats_peers_mrtg( reply );
 | 
					 | 
				
			||||||
    case TASK_STATS_TORRENTS:
 | 
					 | 
				
			||||||
      return stats_torrents_mrtg( reply );
 | 
					 | 
				
			||||||
    case TASK_STATS_TORADDREM:
 | 
					    case TASK_STATS_TORADDREM:
 | 
				
			||||||
      return stats_toraddrem_mrtg( reply );
 | 
					      return stats_toraddrem_mrtg( reply );
 | 
				
			||||||
    case TASK_STATS_STARTSTOP:
 | 
					    case TASK_STATS_STARTSTOP:
 | 
				
			||||||
      return stats_startstop_mrtg( reply );
 | 
					      return stats_startstop_mrtg( reply );
 | 
				
			||||||
    case TASK_STATS_SLASH24S:
 | 
					 | 
				
			||||||
      return stats_slash24s_txt( reply, 25, 16 );
 | 
					 | 
				
			||||||
    case TASK_STATS_TOP5:
 | 
					 | 
				
			||||||
      return stats_top5_txt( reply );
 | 
					 | 
				
			||||||
    case TASK_STATS_FULLSCRAPE:
 | 
					    case TASK_STATS_FULLSCRAPE:
 | 
				
			||||||
      return stats_fullscrapes_mrtg( reply );
 | 
					      return stats_fullscrapes_mrtg( reply );
 | 
				
			||||||
    case TASK_STATS_HTTPERRORS:
 | 
					    case TASK_STATS_HTTPERRORS:
 | 
				
			||||||
@ -484,12 +528,37 @@ size_t return_stats_for_tracker( char *reply, int mode, int format ) {
 | 
				
			|||||||
#ifdef WANT_LOG_NETWORKS
 | 
					#ifdef WANT_LOG_NETWORKS
 | 
				
			||||||
    case TASK_STATS_BUSY_NETWORKS:
 | 
					    case TASK_STATS_BUSY_NETWORKS:
 | 
				
			||||||
      return stats_return_busy_networks( reply );
 | 
					      return stats_return_busy_networks( reply );
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _DEBUG_VECTOR
 | 
				
			||||||
 | 
					    case TASK_STATS_VECTOR_DEBUG:
 | 
				
			||||||
 | 
					      return vector_info( reply );
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void stats_make( int *iovec_entries, struct iovec **iovector, ot_tasktype mode ) {
 | 
				
			||||||
 | 
					  char *r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *iovec_entries = 0;
 | 
				
			||||||
 | 
					  *iovector      = NULL;
 | 
				
			||||||
 | 
					  if( !( r = iovec_increase( iovec_entries, iovector, OT_STATS_TMPSIZE ) ) )
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  switch( mode & TASK_TASK_MASK ) {
 | 
				
			||||||
 | 
					    case TASK_STATS_TORRENTS:    r += stats_torrents_mrtg( r );             break;
 | 
				
			||||||
 | 
					    case TASK_STATS_PEERS:       r += stats_peers_mrtg( r );                break;      
 | 
				
			||||||
 | 
					    case TASK_STATS_SLASH24S:    r += stats_slash24s_txt( r, 25, 16 );      break;
 | 
				
			||||||
 | 
					    case TASK_STATS_TOP10:       r += stats_top10_txt( r );                 break;
 | 
				
			||||||
 | 
					    case TASK_STATS_MEMORY:      r += stats_vector_usage( r );              break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      iovec_free(iovec_entries, iovector);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  iovec_fixlast( iovec_entries, iovector, r );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ) {
 | 
					void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data ) {
 | 
				
			||||||
  switch( event ) {
 | 
					  switch( event ) {
 | 
				
			||||||
    case EVENT_ACCEPT:
 | 
					    case EVENT_ACCEPT:
 | 
				
			||||||
@ -537,12 +606,34 @@ void stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void * stats_worker( void * args ) {
 | 
				
			||||||
 | 
					  int iovec_entries;
 | 
				
			||||||
 | 
					  struct iovec *iovector;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  args = args;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  while( 1 ) {
 | 
				
			||||||
 | 
					    ot_tasktype tasktype = TASK_STATS;
 | 
				
			||||||
 | 
					    ot_taskid   taskid   = mutex_workqueue_poptask( &tasktype );
 | 
				
			||||||
 | 
					    stats_make( &iovec_entries, &iovector, tasktype );
 | 
				
			||||||
 | 
					    if( mutex_workqueue_pushresult( taskid, iovec_entries, iovector ) )
 | 
				
			||||||
 | 
					      iovec_free( &iovec_entries, &iovector );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void stats_deliver( int64 socket, int tasktype ) {
 | 
				
			||||||
 | 
					  mutex_workqueue_pushtask( socket, tasktype );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static pthread_t thread_id;
 | 
				
			||||||
void stats_init( ) {
 | 
					void stats_init( ) {
 | 
				
			||||||
  ot_start_time = g_now;
 | 
					  ot_start_time = g_now;
 | 
				
			||||||
 | 
					  pthread_create( &thread_id, NULL, stats_worker, NULL );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void stats_deinit( ) {
 | 
					void stats_deinit( ) {
 | 
				
			||||||
 | 
					  pthread_cancel( thread_id );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *g_version_stats_c = "$Source$: $Revision$\n";
 | 
					const char *g_version_stats_c = "$Source$: $Revision$\n";
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,7 @@ enum {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void   stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data );
 | 
					void   stats_issue_event( ot_status_event event, PROTO_FLAG proto, uint32_t event_data );
 | 
				
			||||||
 | 
					void   stats_deliver( int64 socket, int tasktype );
 | 
				
			||||||
size_t return_stats_for_tracker( char *reply, int mode, int format );
 | 
					size_t return_stats_for_tracker( char *reply, int mode, int format );
 | 
				
			||||||
size_t stats_return_tracker_version( char *reply );
 | 
					size_t stats_return_tracker_version( char *reply );
 | 
				
			||||||
void   stats_init( );
 | 
					void   stats_init( );
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user