diff options
Diffstat (limited to 'ot_clean.c')
| -rw-r--r-- | ot_clean.c | 137 | 
1 files changed, 71 insertions, 66 deletions
| @@ -5,89 +5,91 @@ | |||
| 5 | 5 | ||
| 6 | /* System */ | 6 | /* System */ | 
| 7 | #include <pthread.h> | 7 | #include <pthread.h> | 
| 8 | #include <unistd.h> | ||
| 9 | #include <string.h> | 8 | #include <string.h> | 
| 9 | #include <unistd.h> | ||
| 10 | 10 | ||
| 11 | /* Libowfat */ | 11 | /* Libowfat */ | 
| 12 | #include "io.h" | 12 | #include "io.h" | 
| 13 | 13 | ||
| 14 | /* Opentracker */ | 14 | /* Opentracker */ | 
| 15 | #include "trackerlogic.h" | 15 | #include "ot_accesslist.h" | 
| 16 | #include "ot_mutex.h" | ||
| 17 | #include "ot_vector.h" | ||
| 18 | #include "ot_clean.h" | 16 | #include "ot_clean.h" | 
| 17 | #include "ot_mutex.h" | ||
| 19 | #include "ot_stats.h" | 18 | #include "ot_stats.h" | 
| 19 | #include "ot_vector.h" | ||
| 20 | #include "trackerlogic.h" | ||
| 20 | 21 | ||
| 21 | /* Returns amount of removed peers */ | 22 | /* Returns amount of removed peers */ | 
| 22 | static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) { | 23 | static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders) { | 
| 23 | ot_peer *last_peer = peers + peer_count, *insert_point; | 24 | ot_peer *last_peer = peers + peer_count * peer_size, *insert_point; | 
| 24 | time_t timediff; | ||
| 25 | 25 | ||
| 26 | /* Two scan modes: unless there is one peer removed, just increase ot_peertime */ | 26 | /* Two scan modes: unless there is one peer removed, just increase ot_peertime */ | 
| 27 | while( peers < last_peer ) { | 27 | while (peers < last_peer) { | 
| 28 | if( ( timediff = timedout + OT_PEERTIME( peers ) ) >= OT_PEER_TIMEOUT ) | 28 | time_t timediff = timedout + OT_PEERTIME(peers, peer_size); | 
| 29 | if (timediff >= OT_PEER_TIMEOUT) | ||
| 29 | break; | 30 | break; | 
| 30 | OT_PEERTIME( peers++ ) = timediff; | 31 | OT_PEERTIME(peers, peer_size) = timediff; | 
| 32 | peers += peer_size; | ||
| 33 | } | ||
| 34 | |||
| 35 | /* If we at least remove one peer, we have to copy */ | ||
| 36 | for (insert_point = peers; peers < last_peer; peers += peer_size) { | ||
| 37 | time_t timediff = timedout + OT_PEERTIME(peers, peer_size); | ||
| 38 | |||
| 39 | if (timediff < OT_PEER_TIMEOUT) { | ||
| 40 | OT_PEERTIME(peers, peer_size) = timediff; | ||
| 41 | memcpy(insert_point, peers, peer_size); | ||
| 42 | insert_point += peer_size; | ||
| 43 | } else if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING) | ||
| 44 | (*removed_seeders)++; | ||
| 31 | } | 45 | } | 
| 32 | 46 | ||
| 33 | /* If we at least remove one peer, we have to copy */ | 47 | return (peers - insert_point) / peer_size; | 
| 34 | insert_point = peers; | ||
| 35 | while( peers < last_peer ) | ||
| 36 | if( ( timediff = timedout + OT_PEERTIME( peers ) ) < OT_PEER_TIMEOUT ) { | ||
| 37 | OT_PEERTIME( peers ) = timediff; | ||
| 38 | memcpy( insert_point++, peers++, sizeof(ot_peer)); | ||
| 39 | } else | ||
| 40 | if( OT_PEERFLAG( peers++ ) & PEER_FLAG_SEEDING ) | ||
| 41 | (*removed_seeders)++; | ||
| 42 | |||
| 43 | return peers - insert_point; | ||
| 44 | } | 48 | } | 
| 45 | 49 | ||
| 46 | /* Clean a single torrent | 50 | int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { | 
| 47 | return 1 if torrent timed out | 51 | ot_vector *peer_vector = &peer_list->peers; | 
| 48 | */ | 52 | time_t timedout = (time_t)(g_now_minutes - peer_list->base); | 
| 49 | int clean_single_torrent( ot_torrent *torrent ) { | 53 | int num_buckets = 1, removed_seeders = 0; | 
| 50 | ot_peerlist *peer_list = torrent->peer_list; | ||
| 51 | ot_vector *bucket_list = &peer_list->peers; | ||
| 52 | time_t timedout = (time_t)( g_now_minutes - peer_list->base ); | ||
| 53 | int num_buckets = 1, removed_seeders = 0; | ||
| 54 | 54 | ||
| 55 | /* No need to clean empty torrent */ | 55 | /* No need to clean empty torrent */ | 
| 56 | if( !timedout ) | 56 | if (!timedout) | 
| 57 | return 0; | 57 | return 0; | 
| 58 | 58 | ||
| 59 | /* Torrent has idled out */ | 59 | /* Torrent has idled out */ | 
| 60 | if( timedout > OT_TORRENT_TIMEOUT ) | 60 | if (timedout > OT_TORRENT_TIMEOUT) | 
| 61 | return 1; | 61 | return 1; | 
| 62 | 62 | ||
| 63 | /* Nothing to be cleaned here? Test if torrent is worth keeping */ | 63 | /* Nothing to be cleaned here? Test if torrent is worth keeping */ | 
| 64 | if( timedout > OT_PEER_TIMEOUT ) { | 64 | if (timedout > OT_PEER_TIMEOUT) { | 
| 65 | if( !peer_list->peer_count ) | 65 | if (!peer_list->peer_count) | 
| 66 | return peer_list->down_count ? 0 : 1; | 66 | return peer_list->down_count ? 0 : 1; | 
| 67 | timedout = OT_PEER_TIMEOUT; | 67 | timedout = OT_PEER_TIMEOUT; | 
| 68 | } | 68 | } | 
| 69 | 69 | ||
| 70 | if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { | 70 | if (OT_PEERLIST_HASBUCKETS(peer_list)) { | 
| 71 | num_buckets = bucket_list->size; | 71 | num_buckets = peer_vector->size; | 
| 72 | bucket_list = (ot_vector *)bucket_list->data; | 72 | peer_vector = (ot_vector *)peer_vector->data; | 
| 73 | } | 73 | } | 
| 74 | 74 | ||
| 75 | while( num_buckets-- ) { | 75 | while (num_buckets--) { | 
| 76 | size_t removed_peers = clean_single_bucket( bucket_list->data, bucket_list->size, timedout, &removed_seeders ); | 76 | size_t removed_peers = clean_single_bucket(peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders); | 
| 77 | peer_list->peer_count -= removed_peers; | 77 | peer_list->peer_count -= removed_peers; | 
| 78 | bucket_list->size -= removed_peers; | 78 | peer_vector->size -= removed_peers; | 
| 79 | if( bucket_list->size < removed_peers ) | 79 | if (removed_peers) | 
| 80 | vector_fixup_peers( bucket_list ); | 80 | vector_fixup_peers(peer_vector, peer_size); | 
| 81 | ++bucket_list; | 81 | |
| 82 | /* Skip to next bucket, a vector containing peers */ | ||
| 83 | ++peer_vector; | ||
| 82 | } | 84 | } | 
| 83 | 85 | ||
| 84 | peer_list->seed_count -= removed_seeders; | 86 | peer_list->seed_count -= removed_seeders; | 
| 85 | 87 | ||
| 86 | /* See, if we need to convert a torrent from simple vector to bucket list */ | 88 | /* See if we need to convert a torrent from simple vector to bucket list */ | 
| 87 | if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) ) | 89 | if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list)) | 
| 88 | vector_redistribute_buckets( peer_list ); | 90 | vector_redistribute_buckets(peer_list, peer_size); | 
| 89 | 91 | ||
| 90 | if( peer_list->peer_count ) | 92 | if (peer_list->peer_count) | 
| 91 | peer_list->base = g_now_minutes; | 93 | peer_list->base = g_now_minutes; | 
| 92 | else { | 94 | else { | 
| 93 | /* When we got here, the last time that torrent | 95 | /* When we got here, the last time that torrent | 
| @@ -95,45 +97,48 @@ int clean_single_torrent( ot_torrent *torrent ) { | |||
| 95 | peer_list->base = g_now_minutes - OT_PEER_TIMEOUT; | 97 | peer_list->base = g_now_minutes - OT_PEER_TIMEOUT; | 
| 96 | } | 98 | } | 
| 97 | return 0; | 99 | return 0; | 
| 100 | } | ||
| 98 | 101 | ||
| 102 | /* Clean a single torrent | ||
| 103 | return 1 if torrent timed out | ||
| 104 | */ | ||
| 105 | int clean_single_torrent(ot_torrent *torrent) { | ||
| 106 | return clean_single_peer_list(torrent->peer_list6, OT_PEER_SIZE6) * clean_single_peer_list(torrent->peer_list4, OT_PEER_SIZE4); | ||
| 99 | } | 107 | } | 
| 100 | 108 | ||
| 101 | /* Clean up all peers in current bucket, remove timedout pools and | 109 | /* Clean up all peers in current bucket, remove timedout pools and | 
| 102 | torrents */ | 110 | torrents */ | 
| 103 | static void * clean_worker( void * args ) { | 111 | static void *clean_worker(void *args) { | 
| 104 | (void) args; | 112 | (void)args; | 
| 105 | while( 1 ) { | 113 | while (1) { | 
| 106 | int bucket = OT_BUCKET_COUNT; | 114 | int bucket = OT_BUCKET_COUNT; | 
| 107 | while( bucket-- ) { | 115 | while (bucket--) { | 
| 108 | ot_vector *torrents_list = mutex_bucket_lock( bucket ); | 116 | ot_vector *torrents_list = mutex_bucket_lock(bucket); | 
| 109 | size_t toffs; | 117 | size_t toffs; | 
| 110 | int delta_torrentcount = 0; | 118 | int delta_torrentcount = 0; | 
| 111 | 119 | ||
| 112 | for( toffs=0; toffs<torrents_list->size; ++toffs ) { | 120 | for (toffs = 0; toffs < torrents_list->size; ++toffs) { | 
| 113 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs; | 121 | ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + toffs; | 
| 114 | if( clean_single_torrent( torrent ) ) { | 122 | if (clean_single_torrent(torrent)) { | 
| 115 | vector_remove_torrent( torrents_list, torrent ); | 123 | vector_remove_torrent(torrents_list, torrent); | 
| 116 | --delta_torrentcount; | 124 | --delta_torrentcount; | 
| 117 | --toffs; | 125 | --toffs; | 
| 118 | } | 126 | } | 
| 119 | } | 127 | } | 
| 120 | mutex_bucket_unlock( bucket, delta_torrentcount ); | 128 | mutex_bucket_unlock(bucket, delta_torrentcount); | 
| 121 | if( !g_opentracker_running ) | 129 | if (!g_opentracker_running) | 
| 122 | return NULL; | 130 | return NULL; | 
| 123 | usleep( OT_CLEAN_SLEEP ); | 131 | usleep(OT_CLEAN_SLEEP); | 
| 124 | } | 132 | } | 
| 125 | stats_cleanup(); | 133 | stats_cleanup(); | 
| 134 | #ifdef WANT_ACCESSLIST | ||
| 135 | accesslist_cleanup(); | ||
| 136 | #endif | ||
| 126 | } | 137 | } | 
| 127 | return NULL; | 138 | return NULL; | 
| 128 | } | 139 | } | 
| 129 | 140 | ||
| 130 | static pthread_t thread_id; | 141 | static pthread_t thread_id; | 
| 131 | void clean_init( void ) { | 142 | void clean_init(void) { pthread_create(&thread_id, NULL, clean_worker, NULL); } | 
| 132 | pthread_create( &thread_id, NULL, clean_worker, NULL ); | ||
| 133 | } | ||
| 134 | |||
| 135 | void clean_deinit( void ) { | ||
| 136 | pthread_cancel( thread_id ); | ||
| 137 | } | ||
| 138 | 143 | ||
| 139 | const char *g_version_clean_c = "$Source$: $Revision$\n"; | 144 | void clean_deinit(void) { pthread_cancel(thread_id); } | 
