summaryrefslogtreecommitdiff
path: root/ot_clean.c
diff options
context:
space:
mode:
authorerdgeist <>2008-11-28 22:21:10 +0000
committererdgeist <>2008-11-28 22:21:10 +0000
commit334c6e4bbb97a4c0656e1b07c3e6a565f68eae2b (patch)
treef84ad28c39b32d0906e32e8ba5e461ecdaed7799 /ot_clean.c
parentff6c0339c13a6b42149ba91da14dbb824307cea7 (diff)
The BIG refactoring [tm]. Too many changes to count them. If it doesn't suite you, revert to last version.
Diffstat (limited to 'ot_clean.c')
-rw-r--r--ot_clean.c148
1 files changed, 71 insertions, 77 deletions
diff --git a/ot_clean.c b/ot_clean.c
index 4f18433..e4d8ca2 100644
--- a/ot_clean.c
+++ b/ot_clean.c
@@ -7,29 +7,53 @@
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#include <pthread.h> 9#include <pthread.h>
10#include <sys/uio.h>
11#include <unistd.h> 10#include <unistd.h>
11#include <stdint.h>
12 12
13/* Libowfat */ 13/* Libowfat */
14#include "byte.h"
15#include "io.h" 14#include "io.h"
16 15
17/* Opentracker */ 16/* Opentracker */
18#include "trackerlogic.h" 17#include "trackerlogic.h"
19#include "ot_mutex.h" 18#include "ot_mutex.h"
19#include "ot_vector.h"
20#include "ot_clean.h"
21
22/* Returns amount of removed peers */
23static ssize_t clean_single_bucket( ot_peer *peers, size_t peer_count, time_t timedout, int *removed_seeders ) {
24 ot_peer *last_peer = peers + peer_count, *insert_point;
25 time_t timediff;
26
27 /* Two scan modes: unless there is one peer removed, just increase ot_peertime */
28 while( peers < last_peer ) {
29 if( ( timediff = timedout + OT_PEERTIME( peers ) ) >= OT_PEER_TIMEOUT )
30 break;
31 OT_PEERTIME( peers++ ) = timediff;
32 }
33
34 /* If we at least remove one peer, we have to copy */
35 insert_point = peers;
36 while( peers < last_peer )
37 if( ( timediff = timedout + OT_PEERTIME( peers ) ) < OT_PEER_TIMEOUT ) {
38 OT_PEERTIME( peers ) = timediff;
39 *(uint64_t*)(insert_point++) = *(uint64_t*)(peers++);
40 } else
41 if( OT_FLAG( peers++ ) & PEER_FLAG_SEEDING )
42 (*removed_seeders)++;
43
44 return peers - insert_point;
45}
20 46
21/* Clean a single torrent 47/* Clean a single torrent
22 return 1 if torrent timed out 48 return 1 if torrent timed out
23*/ 49*/
24int clean_single_torrent( ot_torrent *torrent ) { 50int clean_single_torrent( ot_torrent *torrent ) {
25 ot_peerlist *peer_list = torrent->peer_list; 51 ot_peerlist *peer_list = torrent->peer_list;
26 size_t peers_count = 0, seeds_count; 52 ot_vector *bucket_list = &peer_list->peers;
27 time_t timedout = (int)( NOW - peer_list->base ); 53 time_t timedout = (time_t)( g_now_minutes - peer_list->base );
28 int i; 54 int num_buckets = 1, removed_seeders = 0;
29#ifdef WANT_SYNC_BATCH
30 char *new_peers;
31#endif
32 55
56 /* No need to clean empty torrent */
33 if( !timedout ) 57 if( !timedout )
34 return 0; 58 return 0;
35 59
@@ -38,97 +62,67 @@ int clean_single_torrent( ot_torrent *torrent ) {
38 return 1; 62 return 1;
39 63
40 /* Nothing to be cleaned here? Test if torrent is worth keeping */ 64 /* Nothing to be cleaned here? Test if torrent is worth keeping */
41 if( timedout > OT_POOLS_COUNT ) { 65 if( timedout > OT_PEER_TIMEOUT ) {
42 if( !peer_list->peer_count ) 66 if( !peer_list->peer_count )
43 return peer_list->down_count ? 0 : 1; 67 return peer_list->down_count ? 0 : 1;
44 timedout = OT_POOLS_COUNT; 68 timedout = OT_PEER_TIMEOUT;
45 } 69 }
46 70
47 /* Release vectors that have timed out */ 71 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) {
48 for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i ) 72 num_buckets = bucket_list->size;
49 free( peer_list->peers[i].data); 73 bucket_list = (ot_vector *)bucket_list->data;
50
51 /* Shift vectors back by the amount of pools that were shifted out */
52 memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) );
53 byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout );
54
55 /* Shift back seed counts as well */
56 memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) );
57 byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout );
58
59#ifdef WANT_SYNC_BATCH
60 /* Save the block modified within last OT_POOLS_TIMEOUT */
61 if( peer_list->peers[1].size &&
62 ( new_peers = realloc( peer_list->changeset.data, sizeof( ot_peer ) * peer_list->peers[1].size ) ) )
63 {
64 memmove( new_peers, peer_list->peers[1].data, peer_list->peers[1].size );
65 peer_list->changeset.data = new_peers;
66 peer_list->changeset.size = sizeof( ot_peer ) * peer_list->peers[1].size;
67 } else {
68 free( peer_list->changeset.data );
69
70 memset( &peer_list->changeset, 0, sizeof( ot_vector ) );
71 } 74 }
72#endif
73 75
74 peers_count = seeds_count = 0; 76 while( num_buckets-- ) {
75 for( i = 0; i < OT_POOLS_COUNT; ++i ) { 77 size_t removed_peers = clean_single_bucket( bucket_list->data, bucket_list->size, timedout, &removed_seeders );
76 peers_count += peer_list->peers[i].size; 78 peer_list->peer_count -= removed_peers;
77 seeds_count += peer_list->seed_counts[i]; 79 bucket_list->size -= removed_peers;
80 if( bucket_list->size < removed_peers )
81 vector_fixup_peers( bucket_list );
82 ++bucket_list;
78 } 83 }
79 peer_list->seed_count = seeds_count;
80 peer_list->peer_count = peers_count;
81 84
82 if( peers_count ) 85 peer_list->seed_count -= removed_seeders;
83 peer_list->base = NOW; 86
87 /* See, if we need to convert a torrent from simple vector to bucket list */
88 if( ( peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT ) || OT_PEERLIST_HASBUCKETS(peer_list) )
89 vector_redistribute_buckets( peer_list );
90
91 if( peer_list->peer_count )
92 peer_list->base = g_now_minutes;
84 else { 93 else {
85 /* When we got here, the last time that torrent 94 /* When we got here, the last time that torrent
86 has been touched is OT_POOLS_COUNT units before */ 95 has been touched is OT_PEER_TIMEOUT Minutes before */
87 peer_list->base = NOW - OT_POOLS_COUNT; 96 peer_list->base = g_now_minutes - OT_PEER_TIMEOUT;
88 } 97 }
89 return 0; 98 return 0;
90}
91
92static void clean_make() {
93 int bucket;
94
95 for( bucket = OT_BUCKET_COUNT - 1; bucket >= 0; --bucket ) {
96 ot_vector *torrents_list = mutex_bucket_lock( bucket );
97 size_t toffs;
98 99
99 for( toffs=0; toffs<torrents_list->size; ++toffs ) {
100 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs;
101 if( clean_single_torrent( torrent ) ) {
102 vector_remove_torrent( torrents_list, torrent );
103 --toffs; continue;
104 }
105 }
106 mutex_bucket_unlock( bucket );
107
108 /* We want the cleanup to be spread about 2 Minutes to reduce load spikes
109 during cleanup. Sleeping around two minutes was chosen to allow enough
110 time for the actual work and fluctuations in timer. */
111 usleep( ( 2 * 60 * 1000000 ) / OT_BUCKET_COUNT );
112 }
113} 100}
114 101
115/* Clean up all peers in current bucket, remove timedout pools and 102/* Clean up all peers in current bucket, remove timedout pools and
116 torrents */ 103 torrents */
117static void * clean_worker( void * args ) { 104static void * clean_worker( void * args ) {
118 args = args; 105 args=args;
119 while( 1 ) { 106 while( 1 ) {
120 ot_tasktype tasktype = TASK_CLEAN; 107 int bucket = OT_BUCKET_COUNT;
121 ot_taskid taskid = mutex_workqueue_poptask( &tasktype ); 108 while( bucket-- ) {
122 clean_make( ); 109 ot_vector *torrents_list = mutex_bucket_lock( bucket );
123 mutex_workqueue_pushsuccess( taskid ); 110 size_t toffs;
111
112 for( toffs=0; toffs<torrents_list->size; ++toffs ) {
113 ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + toffs;
114 if( clean_single_torrent( torrent ) ) {
115 vector_remove_torrent( torrents_list, torrent );
116 --toffs; continue;
117 }
118 }
119 mutex_bucket_unlock( bucket );
120 usleep( OT_CLEAN_SLEEP );
121 }
124 } 122 }
125 return NULL; 123 return NULL;
126} 124}
127 125
128void clean_all_torrents( ) {
129 mutex_workqueue_pushtask( 0, TASK_CLEAN );
130}
131
132static pthread_t thread_id; 126static pthread_t thread_id;
133void clean_init( void ) { 127void clean_init( void ) {
134 pthread_create( &thread_id, NULL, clean_worker, NULL ); 128 pthread_create( &thread_id, NULL, clean_worker, NULL );