diff options
author | erdgeist <> | 2007-10-27 14:06:07 +0000 |
---|---|---|
committer | erdgeist <> | 2007-10-27 14:06:07 +0000 |
commit | b19bbd6a850ecd51180dfea6e025a032fb2f1fe1 (patch) | |
tree | 84b17f4b10344fcb7addf653c8fdc10a4980fdb5 /trackerlogic.c | |
parent | 72c72bb3a18655925b6a6d3d1df5af3600da3b58 (diff) |
Number of buckets is 1024 now
Clean all torrents now only cleans one bucket at a time
All torrents that are being worked upon in an announce are being cleaned on demoand
torrent's peer lists now keep extra counts for seeds and peers to speed up scrape and announce
Sync has gone for now. I will think up a new way to implement. The old one was way to slow.
Diffstat (limited to 'trackerlogic.c')
-rw-r--r-- | trackerlogic.c | 348 |
1 files changed, 168 insertions, 180 deletions
diff --git a/trackerlogic.c b/trackerlogic.c index 3560834..3aa3752 100644 --- a/trackerlogic.c +++ b/trackerlogic.c | |||
@@ -20,7 +20,8 @@ | |||
20 | #include "byte.h" | 20 | #include "byte.h" |
21 | 21 | ||
22 | /* GLOBAL VARIABLES */ | 22 | /* GLOBAL VARIABLES */ |
23 | static ot_vector all_torrents[256]; | 23 | static ot_vector all_torrents[OT_BUCKET_COUNT]; |
24 | static ot_time all_torrents_clean[OT_BUCKET_COUNT]; | ||
24 | static ot_vector changeset; | 25 | static ot_vector changeset; |
25 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) | 26 | #if defined ( WANT_BLACKLISTING ) || defined( WANT_CLOSED_TRACKER ) |
26 | static ot_vector accesslist; | 27 | static ot_vector accesslist; |
@@ -28,7 +29,8 @@ static ot_vector accesslist; | |||
28 | #endif | 29 | #endif |
29 | 30 | ||
30 | static size_t changeset_size = 0; | 31 | static size_t changeset_size = 0; |
31 | static time_t last_clean_time = 0; | 32 | |
33 | static int clean_single_torrent( ot_torrent *torrent ); | ||
32 | 34 | ||
33 | /* Converter function from memory to human readable hex strings | 35 | /* Converter function from memory to human readable hex strings |
34 | - definitely not thread safe!!! | 36 | - definitely not thread safe!!! |
@@ -127,19 +129,10 @@ static void free_peerlist( ot_peerlist *peer_list ) { | |||
127 | free( peer_list ); | 129 | free( peer_list ); |
128 | } | 130 | } |
129 | 131 | ||
130 | /* This is the non-generic delete from vector-operation specialized for torrents in buckets. | 132 | static void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { |
131 | it returns 0 if the hash wasn't found in vector | ||
132 | 1 if the torrent was removed from vector | ||
133 | */ | ||
134 | static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) { | ||
135 | int exactmatch; | ||
136 | ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; | 133 | ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; |
137 | ot_torrent *match; | ||
138 | 134 | ||
139 | if( !vector->size ) return 0; | 135 | if( !vector->size ) return; |
140 | |||
141 | match = binary_search( hash, vector->data, vector->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | ||
142 | if( !exactmatch ) return 0; | ||
143 | 136 | ||
144 | /* If this is being called after a unsuccessful malloc() for peer_list | 137 | /* If this is being called after a unsuccessful malloc() for peer_list |
145 | in add_peer_to_torrent, match->peer_list actually might be NULL */ | 138 | in add_peer_to_torrent, match->peer_list actually might be NULL */ |
@@ -150,14 +143,13 @@ static int vector_remove_torrent( ot_vector *vector, ot_hash *hash ) { | |||
150 | vector->space /= OT_VECTOR_SHRINK_RATIO; | 143 | vector->space /= OT_VECTOR_SHRINK_RATIO; |
151 | vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); | 144 | vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); |
152 | } | 145 | } |
153 | return 1; | ||
154 | } | 146 | } |
155 | 147 | ||
156 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset ) { | 148 | ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changeset ) { |
157 | int exactmatch; | 149 | int exactmatch; |
158 | ot_torrent *torrent; | 150 | ot_torrent *torrent; |
159 | ot_peer *peer_dest; | 151 | ot_peer *peer_dest; |
160 | ot_vector *torrents_list = &all_torrents[*hash[0]], *peer_pool; | 152 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ), *peer_pool; |
161 | int base_pool = 0; | 153 | int base_pool = 0; |
162 | 154 | ||
163 | #ifdef WANT_ACCESS_CONTROL | 155 | #ifdef WANT_ACCESS_CONTROL |
@@ -179,13 +171,14 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changese | |||
179 | memmove( &torrent->hash, hash, sizeof( ot_hash ) ); | 171 | memmove( &torrent->hash, hash, sizeof( ot_hash ) ); |
180 | 172 | ||
181 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { | 173 | if( !( torrent->peer_list = malloc( sizeof (ot_peerlist) ) ) ) { |
182 | vector_remove_torrent( torrents_list, hash ); | 174 | vector_remove_torrent( torrents_list, torrent ); |
183 | return NULL; | 175 | return NULL; |
184 | } | 176 | } |
185 | 177 | ||
186 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); | 178 | byte_zero( torrent->peer_list, sizeof( ot_peerlist ) ); |
187 | torrent->peer_list->base = NOW; | 179 | torrent->peer_list->base = NOW; |
188 | } | 180 | } else |
181 | clean_single_torrent( torrent ); | ||
189 | 182 | ||
190 | /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ | 183 | /* Sanitize flags: Whoever claims to have completed download, must be a seeder */ |
191 | if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) | 184 | if( ( OT_FLAG( peer ) & ( PEER_FLAG_COMPLETED | PEER_FLAG_SEEDING ) ) == PEER_FLAG_COMPLETED ) |
@@ -208,27 +201,37 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changese | |||
208 | if( !exactmatch ) { | 201 | if( !exactmatch ) { |
209 | int i; | 202 | int i; |
210 | memmove( peer_dest, peer, sizeof( ot_peer ) ); | 203 | memmove( peer_dest, peer, sizeof( ot_peer ) ); |
204 | torrent->peer_list->peer_count++; | ||
211 | 205 | ||
212 | if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) | 206 | if( OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) |
213 | torrent->peer_list->downloaded++; | 207 | torrent->peer_list->down_count++; |
214 | 208 | ||
215 | if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) | 209 | if( OT_FLAG(peer) & PEER_FLAG_SEEDING ) { |
216 | torrent->peer_list->seed_count[ base_pool ]++; | 210 | torrent->peer_list->seed_counts[ base_pool ]++; |
211 | torrent->peer_list->seed_count++; | ||
212 | } | ||
217 | 213 | ||
218 | for( i= base_pool + 1; i<OT_POOLS_COUNT; ++i ) { | 214 | for( i= base_pool + 1; i<OT_POOLS_COUNT; ++i ) { |
219 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) { | 215 | switch( vector_remove_peer( &torrent->peer_list->peers[i], peer, 0 ) ) { |
220 | case 0: continue; | 216 | case 0: continue; |
221 | case 2: torrent->peer_list->seed_count[i]--; | 217 | case 2: torrent->peer_list->seed_counts[i]--; |
222 | case 1: default: return torrent; | 218 | torrent->peer_list->seed_count--; |
219 | case 1: default: | ||
220 | torrent->peer_list->peer_count--; | ||
221 | return torrent; | ||
223 | } | 222 | } |
224 | } | 223 | } |
225 | } else { | 224 | } else { |
226 | if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) | 225 | if( (OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && !(OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) { |
227 | torrent->peer_list->seed_count[ base_pool ]--; | 226 | torrent->peer_list->seed_counts[ base_pool ]--; |
228 | if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) | 227 | torrent->peer_list->seed_count--; |
229 | torrent->peer_list->seed_count[ base_pool ]++; | 228 | } |
229 | if( !(OT_FLAG(peer_dest) & PEER_FLAG_SEEDING ) && (OT_FLAG(peer) & PEER_FLAG_SEEDING ) ) { | ||
230 | torrent->peer_list->seed_counts[ base_pool ]++; | ||
231 | torrent->peer_list->seed_count++; | ||
232 | } | ||
230 | if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) ) | 233 | if( !(OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) && (OT_FLAG( peer ) & PEER_FLAG_COMPLETED ) ) |
231 | torrent->peer_list->downloaded++; | 234 | torrent->peer_list->down_count++; |
232 | if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) | 235 | if( OT_FLAG( peer_dest ) & PEER_FLAG_COMPLETED ) |
233 | OT_FLAG( peer ) |= PEER_FLAG_COMPLETED; | 236 | OT_FLAG( peer ) |= PEER_FLAG_COMPLETED; |
234 | 237 | ||
@@ -245,29 +248,25 @@ ot_torrent *add_peer_to_torrent( ot_hash *hash, ot_peer *peer, int from_changese | |||
245 | * does not yet check not to return self | 248 | * does not yet check not to return self |
246 | */ | 249 | */ |
247 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ) { | 250 | size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply, int is_tcp ) { |
248 | char *r = reply; | 251 | char *r = reply; |
249 | size_t peer_count, seed_count, index; | 252 | ot_peerlist *peer_list = torrent->peer_list; |
250 | 253 | size_t index; | |
251 | for( peer_count = seed_count = index = 0; index < OT_POOLS_COUNT; ++index ) { | ||
252 | peer_count += torrent->peer_list->peers[index].size; | ||
253 | seed_count += torrent->peer_list->seed_count[index]; | ||
254 | } | ||
255 | 254 | ||
256 | if( peer_count < amount ) | 255 | if( peer_list->peer_count < amount ) |
257 | amount = peer_count; | 256 | amount = peer_list->peer_count; |
258 | 257 | ||
259 | if( is_tcp ) | 258 | if( is_tcp ) |
260 | r += sprintf( r, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers%zd:", seed_count, peer_count-seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); | 259 | r += sprintf( r, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers%zd:", peer_list->seed_count, peer_list->peer_count-peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM, 6*amount ); |
261 | else { | 260 | else { |
262 | *(ot_dword*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 261 | *(ot_dword*)(r+0) = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
263 | *(ot_dword*)(r+4) = htonl( peer_count ); | 262 | *(ot_dword*)(r+4) = htonl( peer_list->peer_count ); |
264 | *(ot_dword*)(r+8) = htonl( seed_count ); | 263 | *(ot_dword*)(r+8) = htonl( peer_list->seed_count ); |
265 | r += 12; | 264 | r += 12; |
266 | } | 265 | } |
267 | 266 | ||
268 | if( amount ) { | 267 | if( amount ) { |
269 | unsigned int pool_offset, pool_index = 0;; | 268 | unsigned int pool_offset, pool_index = 0;; |
270 | unsigned int shifted_pc = peer_count; | 269 | unsigned int shifted_pc = peer_list->peer_count; |
271 | unsigned int shifted_step = 0; | 270 | unsigned int shifted_step = 0; |
272 | unsigned int shift = 0; | 271 | unsigned int shift = 0; |
273 | 272 | ||
@@ -279,7 +278,7 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply | |||
279 | 278 | ||
280 | /* Initialize somewhere in the middle of peers so that | 279 | /* Initialize somewhere in the middle of peers so that |
281 | fixpoint's aliasing doesn't alway miss the same peers */ | 280 | fixpoint's aliasing doesn't alway miss the same peers */ |
282 | pool_offset = random() % peer_count; | 281 | pool_offset = random() % peer_list->peer_count; |
283 | 282 | ||
284 | for( index = 0; index < amount; ++index ) { | 283 | for( index = 0; index < amount; ++index ) { |
285 | /* This is the aliased, non shifted range, next value may fall into */ | 284 | /* This is the aliased, non shifted range, next value may fall into */ |
@@ -287,12 +286,12 @@ size_t return_peers_for_torrent( ot_torrent *torrent, size_t amount, char *reply | |||
287 | ( ( index * shifted_step ) >> shift ); | 286 | ( ( index * shifted_step ) >> shift ); |
288 | pool_offset += 1 + random() % diff; | 287 | pool_offset += 1 + random() % diff; |
289 | 288 | ||
290 | while( pool_offset >= torrent->peer_list->peers[pool_index].size ) { | 289 | while( pool_offset >= peer_list->peers[pool_index].size ) { |
291 | pool_offset -= torrent->peer_list->peers[pool_index].size; | 290 | pool_offset -= peer_list->peers[pool_index].size; |
292 | pool_index = ( pool_index + 1 ) % OT_POOLS_COUNT; | 291 | pool_index = ( pool_index + 1 ) % OT_POOLS_COUNT; |
293 | } | 292 | } |
294 | 293 | ||
295 | memmove( r, ((ot_peer*)torrent->peer_list->peers[pool_index].data) + pool_offset, 6 ); | 294 | memmove( r, ((ot_peer*)peer_list->peers[pool_index].data) + pool_offset, 6 ); |
296 | r += 6; | 295 | r += 6; |
297 | } | 296 | } |
298 | } | 297 | } |
@@ -316,10 +315,10 @@ static void fix_mmapallocation( void *buf, size_t old_alloc, size_t new_alloc ) | |||
316 | size_t return_fullscrape_for_tracker( char **reply ) { | 315 | size_t return_fullscrape_for_tracker( char **reply ) { |
317 | size_t torrent_count = 0, j; | 316 | size_t torrent_count = 0, j; |
318 | size_t allocated, replysize; | 317 | size_t allocated, replysize; |
319 | int i, k; | 318 | int i; |
320 | char *r; | 319 | char *r; |
321 | 320 | ||
322 | for( i=0; i<256; ++i ) | 321 | for( i=0; i<OT_BUCKET_COUNT; ++i ) |
323 | torrent_count += all_torrents[i].size; | 322 | torrent_count += all_torrents[i].size; |
324 | 323 | ||
325 | /* one extra for pro- and epilogue */ | 324 | /* one extra for pro- and epilogue */ |
@@ -327,20 +326,15 @@ size_t return_fullscrape_for_tracker( char **reply ) { | |||
327 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; | 326 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; |
328 | 327 | ||
329 | memmove( r, "d5:filesd", 9 ); r += 9; | 328 | memmove( r, "d5:filesd", 9 ); r += 9; |
330 | for( i=0; i<256; ++i ) { | 329 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { |
331 | ot_vector *torrents_list = &all_torrents[i]; | 330 | ot_vector *torrents_list = all_torrents + i; |
332 | for( j=0; j<torrents_list->size; ++j ) { | 331 | for( j=0; j<torrents_list->size; ++j ) { |
333 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 332 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
334 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | 333 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; |
335 | size_t peers = 0, seeds = 0; | 334 | if( peer_list->peer_count || peer_list->down_count ) { |
336 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | ||
337 | peers += peer_list->peers[k].size; | ||
338 | seeds += peer_list->seed_count[k]; | ||
339 | } | ||
340 | if( peers || peer_list->downloaded ) { | ||
341 | *r++='2'; *r++='0'; *r++=':'; | 335 | *r++='2'; *r++='0'; *r++=':'; |
342 | memmove( r, hash, 20 ); r+=20; | 336 | memmove( r, hash, 20 ); r+=20; |
343 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seeds, peer_list->downloaded, peers-seeds ); | 337 | r += sprintf( r, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", peer_list->seed_count, peer_list->down_count, peer_list->peer_count-peer_list->seed_count ); |
344 | } | 338 | } |
345 | } | 339 | } |
346 | } | 340 | } |
@@ -359,19 +353,19 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
359 | int i, k; | 353 | int i, k; |
360 | char *r; | 354 | char *r; |
361 | 355 | ||
362 | for( i=0; i<256; ++i ) { | 356 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { |
363 | ot_vector *torrents_list = &all_torrents[i]; | 357 | ot_vector *torrents_list = all_torrents + i; |
364 | torrent_count += torrents_list->size; | 358 | torrent_count += torrents_list->size; |
365 | } | 359 | } |
366 | 360 | ||
367 | allocated = 256*32 + (43+OT_POOLS_COUNT*32)*torrent_count; | 361 | allocated = OT_BUCKET_COUNT*32 + (43+OT_POOLS_COUNT*32)*torrent_count; |
368 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; | 362 | if( !( r = *reply = mmap( NULL, allocated, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ) ) ) return 0; |
369 | 363 | ||
370 | for( i=0; i<256; ++i ) | 364 | for( i=0; i<OT_BUCKET_COUNT; ++i ) |
371 | r += sprintf( r, "%02X: %08X %08X\n", i, (unsigned int)all_torrents[i].size, (unsigned int)all_torrents[i].space ); | 365 | r += sprintf( r, "%02X: %08X %08X\n", i, (unsigned int)all_torrents[i].size, (unsigned int)all_torrents[i].space ); |
372 | 366 | ||
373 | for( i=0; i<256; ++i ) { | 367 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { |
374 | ot_vector *torrents_list = &all_torrents[i]; | 368 | ot_vector *torrents_list = all_torrents + i; |
375 | for( j=0; j<torrents_list->size; ++j ) { | 369 | for( j=0; j<torrents_list->size; ++j ) { |
376 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 370 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
377 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | 371 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; |
@@ -389,9 +383,8 @@ size_t return_memstat_for_tracker( char **reply ) { | |||
389 | 383 | ||
390 | /* Fetches scrape info for a specific torrent */ | 384 | /* Fetches scrape info for a specific torrent */ |
391 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | 385 | size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { |
392 | int exactmatch, i; | 386 | int exactmatch ; |
393 | size_t peers = 0, seeds = 0; | 387 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ); |
394 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | ||
395 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 388 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
396 | 389 | ||
397 | if( !exactmatch ) { | 390 | if( !exactmatch ) { |
@@ -399,13 +392,14 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
399 | } else { | 392 | } else { |
400 | ot_dword *r = (ot_dword*) reply; | 393 | ot_dword *r = (ot_dword*) reply; |
401 | 394 | ||
402 | for( i=0; i<OT_POOLS_COUNT; ++i ) { | 395 | if( clean_single_torrent( torrent ) ) { |
403 | peers += torrent->peer_list->peers[i].size; | 396 | vector_remove_torrent( torrents_list, torrent ); |
404 | seeds += torrent->peer_list->seed_count[i]; | 397 | memset( reply, 0, 12); |
398 | } else { | ||
399 | r[0] = htonl( torrent->peer_list->seed_count ); | ||
400 | r[1] = htonl( torrent->peer_list->down_count ); | ||
401 | r[2] = htonl( torrent->peer_list->peer_count-torrent->peer_list->seed_count ); | ||
405 | } | 402 | } |
406 | r[0] = htonl( seeds ); | ||
407 | r[1] = htonl( torrent->peer_list->downloaded ); | ||
408 | r[2] = htonl( peers-seeds ); | ||
409 | } | 403 | } |
410 | return 12; | 404 | return 12; |
411 | } | 405 | } |
@@ -413,31 +407,30 @@ size_t return_udp_scrape_for_torrent( ot_hash *hash, char *reply ) { | |||
413 | /* Fetches scrape info for a specific torrent */ | 407 | /* Fetches scrape info for a specific torrent */ |
414 | size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) { | 408 | size_t return_tcp_scrape_for_torrent( ot_hash *hash_list, int amount, char *reply ) { |
415 | char *r = reply; | 409 | char *r = reply; |
416 | int exactmatch, i, j; | 410 | int exactmatch, i; |
417 | 411 | ||
418 | r += sprintf( r, "d5:filesd" ); | 412 | r += sprintf( r, "d5:filesd" ); |
419 | 413 | ||
420 | for( i=0; i<amount; ++i ) { | 414 | for( i=0; i<amount; ++i ) { |
421 | ot_hash *hash = hash_list + i; | 415 | ot_hash *hash = hash_list + i; |
422 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | 416 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ); |
423 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 417 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
424 | size_t peers = 0, seeds = 0; | ||
425 | 418 | ||
426 | if( !exactmatch ) continue; | 419 | if( !exactmatch ) continue; |
427 | 420 | if( clean_single_torrent( torrent ) ) { | |
428 | for( j=0; j<OT_POOLS_COUNT; ++j ) { | 421 | vector_remove_torrent( torrents_list, torrent ); |
429 | peers += torrent->peer_list->peers[j].size; | 422 | } else { |
430 | seeds += torrent->peer_list->seed_count[j]; | 423 | memmove( r, "20:", 3 ); memmove( r+3, hash, 20 ); |
424 | r += sprintf( r+23, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", | ||
425 | torrent->peer_list->seed_count, torrent->peer_list->down_count, torrent->peer_list->peer_count-torrent->peer_list->seed_count ) + 23; | ||
431 | } | 426 | } |
432 | |||
433 | memmove( r, "20:", 3 ); memmove( r+3, hash, 20 ); | ||
434 | r += sprintf( r+23, "d8:completei%zde10:downloadedi%zde10:incompletei%zdee", seeds, torrent->peer_list->downloaded, peers-seeds ) + 23; | ||
435 | } | 427 | } |
436 | 428 | ||
437 | *r++ = 'e'; *r++ = 'e'; | 429 | *r++ = 'e'; *r++ = 'e'; |
438 | return r - reply; | 430 | return r - reply; |
439 | } | 431 | } |
440 | 432 | ||
433 | #ifdef WANT_TRACKER_SYNC | ||
441 | /* Throw away old changeset */ | 434 | /* Throw away old changeset */ |
442 | static void release_changeset( void ) { | 435 | static void release_changeset( void ) { |
443 | ot_byte **changeset_ptrs = (ot_byte**)(changeset.data); | 436 | ot_byte **changeset_ptrs = (ot_byte**)(changeset.data); |
@@ -548,86 +541,91 @@ size_t return_changeset_for_tracker( char **reply ) { | |||
548 | 541 | ||
549 | return r; | 542 | return r; |
550 | } | 543 | } |
544 | #endif | ||
551 | 545 | ||
552 | /* Clean up all torrents, remove timedout pools and | 546 | /* Clean a single torrent |
553 | torrents, also prepare new changeset */ | 547 | return 1 if torrent timed out |
554 | void clean_all_torrents( void ) { | 548 | */ |
555 | int i, k; | 549 | static int clean_single_torrent( ot_torrent *torrent ) { |
556 | size_t j; | 550 | ot_peerlist *peer_list = torrent->peer_list; |
557 | time_t time_now = NOW; | 551 | size_t peers_count = 0, seeds_count; |
558 | size_t peers_count; | 552 | time_t timedout = (int)( NOW - peer_list->base ); |
559 | ot_dword diff; struct timeval tv1, tv2; gettimeofday( &tv1, NULL ); | 553 | int i; |
560 | |||
561 | if( time_now <= last_clean_time ) | ||
562 | return; | ||
563 | last_clean_time = time_now; | ||
564 | |||
565 | release_changeset(); | ||
566 | 554 | ||
567 | for( i=0; i<256; ++i ) { | 555 | /* Torrent has idled out */ |
568 | ot_vector *torrents_list = &all_torrents[i]; | 556 | if( timedout > OT_TORRENT_TIMEOUT ) |
569 | for( j=0; j<torrents_list->size; ++j ) { | 557 | return 1; |
570 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | ||
571 | ot_hash *hash =&( ((ot_torrent*)(torrents_list->data))[j] ).hash; | ||
572 | 558 | ||
573 | time_t timedout = (int)( time_now - peer_list->base ); | 559 | /* Nothing to be cleaned here? Test if torrent is worth keeping */ |
560 | if( timedout > OT_POOLS_COUNT ) { | ||
561 | if( !peer_list->peer_count ) | ||
562 | return peer_list->down_count ? 0 : 1; | ||
563 | timedout = OT_POOLS_COUNT; | ||
564 | } | ||
574 | 565 | ||
575 | /* Torrent has idled out */ | 566 | /* Release vectors that have timed out */ |
576 | if( timedout > OT_TORRENT_TIMEOUT ) { | 567 | for( i = OT_POOLS_COUNT - timedout; i < OT_POOLS_COUNT; ++i ) |
577 | vector_remove_torrent( torrents_list, hash ); | 568 | free( peer_list->peers[i].data); |
578 | --j; continue; | ||
579 | } | ||
580 | 569 | ||
581 | /* If nothing to be cleaned here, handle next torrent */ | 570 | /* Shift vectors back by the amount of pools that were shifted out */ |
582 | if( timedout > OT_POOLS_COUNT ) { | 571 | memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) ); |
572 | byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout ); | ||
583 | 573 | ||
584 | peers_count = 0; | 574 | /* Shift back seed counts as well */ |
585 | for( k = 0; k < OT_POOLS_COUNT; ++k ) | 575 | memmove( peer_list->seed_counts + timedout, peer_list->seed_counts, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) ); |
586 | peers_count += peer_list->peers[k].size; | 576 | byte_zero( peer_list->seed_counts, sizeof( size_t ) * timedout ); |
587 | 577 | ||
588 | if( !peers_count ) { | 578 | /* Save the block modified within last OT_POOLS_TIMEOUT --- XXX no sync for now |
589 | if( !peer_list->downloaded ) { | 579 | if( peer_list->peers[1].size ) |
590 | vector_remove_torrent( torrents_list, hash ); | 580 | add_pool_to_changeset( hash, peer_list->peers[1].data, peer_list->peers[1].size ); |
591 | --j; | 581 | */ |
592 | } | ||
593 | continue; | ||
594 | } | ||
595 | 582 | ||
596 | timedout = OT_POOLS_COUNT; | 583 | peers_count = seeds_count = 0; |
597 | } | 584 | for( i = 0; i < OT_POOLS_COUNT; ++i ) { |
585 | peers_count += peer_list->peers[i].size; | ||
586 | seeds_count += peer_list->seed_counts[i]; | ||
587 | } | ||
588 | peer_list->seed_count = seeds_count; | ||
589 | peer_list->peer_count = peers_count; | ||
598 | 590 | ||
599 | /* Release vectors that have timed out */ | 591 | if( peers_count ) |
600 | for( k = OT_POOLS_COUNT - timedout; k < OT_POOLS_COUNT; ++k ) | 592 | peer_list->base = NOW; |
601 | free( peer_list->peers[k].data); | 593 | else { |
594 | /* When we got here, the last time that torrent | ||
595 | has been touched is OT_POOLS_COUNT units before */ | ||
596 | peer_list->base = NOW - OT_POOLS_COUNT; | ||
597 | } | ||
598 | return 0; | ||
599 | } | ||
602 | 600 | ||
603 | /* Shift vectors back by the amount of pools that were shifted out */ | 601 | /* Clean up all peers in current bucket, remove timedout pools and |
604 | memmove( peer_list->peers + timedout, peer_list->peers, sizeof( ot_vector ) * ( OT_POOLS_COUNT - timedout ) ); | 602 | torrents */ |
605 | byte_zero( peer_list->peers, sizeof( ot_vector ) * timedout ); | 603 | void clean_all_torrents( void ) { |
604 | ot_vector *torrents_list; | ||
605 | size_t i; | ||
606 | static int bucket; | ||
607 | ot_time time_now = NOW; | ||
606 | 608 | ||
607 | /* Shift back seed counts as well */ | 609 | /* No sync for now |
608 | memmove( peer_list->seed_count + timedout, peer_list->seed_count, sizeof( size_t ) * ( OT_POOLS_COUNT - timedout ) ); | 610 | release_changeset(); |
609 | byte_zero( peer_list->seed_count, sizeof( size_t ) * timedout ); | 611 | */ |
610 | 612 | ||
611 | /* Save the block modified within last OT_POOLS_TIMEOUT */ | 613 | /* Search for an uncleaned bucked */ |
612 | if( peer_list->peers[1].size ) | 614 | while( ( all_torrents_clean[bucket] == time_now ) && ( ++bucket < OT_BUCKET_COUNT ) ); |
613 | add_pool_to_changeset( hash, peer_list->peers[1].data, peer_list->peers[1].size ); | 615 | if( bucket >= OT_BUCKET_COUNT ) { |
616 | bucket = 0; return; | ||
617 | } | ||
614 | 618 | ||
615 | peers_count = 0; | 619 | all_torrents_clean[bucket] = time_now; |
616 | for( k = 0; k < OT_POOLS_COUNT; ++k ) | ||
617 | peers_count += peer_list->peers[k].size; | ||
618 | 620 | ||
619 | if( peers_count ) { | 621 | torrents_list = all_torrents + bucket; |
620 | peer_list->base = time_now; | 622 | for( i=0; i<torrents_list->size; ++i ) { |
621 | } else { | 623 | ot_torrent *torrent = ((ot_torrent*)(torrents_list->data)) + i; |
622 | /* When we got here, the last time that torrent | 624 | if( clean_single_torrent( torrent ) ) { |
623 | has been touched is OT_POOLS_COUNT units before */ | 625 | vector_remove_torrent( torrents_list, torrent ); |
624 | peer_list->base = time_now - OT_POOLS_COUNT; | 626 | --i; continue; |
625 | } | ||
626 | } | 627 | } |
627 | } | 628 | } |
628 | |||
629 | gettimeofday( &tv2, NULL ); diff = ( tv2.tv_sec - tv1.tv_sec ) * 1000000 + tv2.tv_usec - tv1.tv_usec; | ||
630 | fprintf( stderr, "Cleanup time taken: %u\n", diff ); | ||
631 | } | 629 | } |
632 | 630 | ||
633 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; | 631 | typedef struct { size_t val; ot_torrent * torrent; } ot_record; |
@@ -637,37 +635,31 @@ size_t return_stats_for_tracker( char *reply, int mode ) { | |||
637 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; | 635 | size_t torrent_count = 0, peer_count = 0, seed_count = 0, j; |
638 | ot_record top5s[5], top5c[5]; | 636 | ot_record top5s[5], top5c[5]; |
639 | char *r = reply; | 637 | char *r = reply; |
640 | int i,k; | 638 | int i; |
641 | 639 | ||
642 | byte_zero( top5s, sizeof( top5s ) ); | 640 | byte_zero( top5s, sizeof( top5s ) ); |
643 | byte_zero( top5c, sizeof( top5c ) ); | 641 | byte_zero( top5c, sizeof( top5c ) ); |
644 | 642 | ||
645 | for( i=0; i<256; ++i ) { | 643 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { |
646 | ot_vector *torrents_list = &all_torrents[i]; | 644 | ot_vector *torrents_list = all_torrents + i; |
647 | torrent_count += torrents_list->size; | 645 | torrent_count += torrents_list->size; |
648 | for( j=0; j<torrents_list->size; ++j ) { | 646 | for( j=0; j<torrents_list->size; ++j ) { |
649 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 647 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
650 | size_t local_peers = 0, local_seeds = 0; | ||
651 | |||
652 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | ||
653 | local_peers += peer_list->peers[k].size; | ||
654 | local_seeds += peer_list->seed_count[k]; | ||
655 | } | ||
656 | if( mode == STATS_TOP5 ) { | 648 | if( mode == STATS_TOP5 ) { |
657 | int idx = 4; while( (idx >= 0) && ( local_peers > top5c[idx].val ) ) --idx; | 649 | int idx = 4; while( (idx >= 0) && ( peer_list->peer_count > top5c[idx].val ) ) --idx; |
658 | if ( idx++ != 4 ) { | 650 | if ( idx++ != 4 ) { |
659 | memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); | 651 | memmove( top5c + idx + 1, top5c + idx, ( 4 - idx ) * sizeof( ot_record ) ); |
660 | top5c[idx].val = local_peers; | 652 | top5c[idx].val = peer_list->peer_count; |
661 | top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | 653 | top5c[idx].torrent = (ot_torrent*)(torrents_list->data) + j; |
662 | } | 654 | } |
663 | idx = 4; while( (idx >= 0) && ( local_seeds > top5s[idx].val ) ) --idx; | 655 | idx = 4; while( (idx >= 0) && ( peer_list->seed_count > top5s[idx].val ) ) --idx; |
664 | if ( idx++ != 4 ) { | 656 | if ( idx++ != 4 ) { |
665 | memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); | 657 | memmove( top5s + idx + 1, top5s + idx, ( 4 - idx ) * sizeof( ot_record ) ); |
666 | top5s[idx].val = local_seeds; | 658 | top5s[idx].val = peer_list->seed_count; |
667 | top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; | 659 | top5s[idx].torrent = (ot_torrent*)(torrents_list->data) + j; |
668 | } | 660 | } |
669 | } | 661 | } |
670 | peer_count += local_peers; seed_count += local_seeds; | 662 | peer_count += peer_list->peer_count; seed_count += peer_list->seed_count; |
671 | } | 663 | } |
672 | } | 664 | } |
673 | if( mode == STATS_TOP5 ) { | 665 | if( mode == STATS_TOP5 ) { |
@@ -708,8 +700,8 @@ size_t return_stats_for_slash24s( char *reply, size_t amount, ot_dword thresh ) | |||
708 | 700 | ||
709 | r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); | 701 | r += sprintf( r, "Stats for all /24s with more than %u announced torrents:\n\n", thresh ); |
710 | 702 | ||
711 | for( i=0; i<256; ++i ) { | 703 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { |
712 | ot_vector *torrents_list = &all_torrents[i]; | 704 | ot_vector *torrents_list = all_torrents + i; |
713 | for( j=0; j<torrents_list->size; ++j ) { | 705 | for( j=0; j<torrents_list->size; ++j ) { |
714 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 706 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
715 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 707 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
@@ -787,8 +779,8 @@ size_t return_stats_for_slash24s_old( char *reply, size_t amount, ot_dword thres | |||
787 | 779 | ||
788 | r += sprintf( r, "Stats for all /24s with more than %d announced torrents:\n\n", ((int)thresh) ); | 780 | r += sprintf( r, "Stats for all /24s with more than %d announced torrents:\n\n", ((int)thresh) ); |
789 | 781 | ||
790 | for( i=0; i<256; ++i ) { | 782 | for( i=0; i<OT_BUCKET_COUNT; ++i ) { |
791 | ot_vector *torrents_list = &all_torrents[i]; | 783 | ot_vector *torrents_list = all_torrents + i; |
792 | for( j=0; j<torrents_list->size; ++j ) { | 784 | for( j=0; j<torrents_list->size; ++j ) { |
793 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; | 785 | ot_peerlist *peer_list = ( ((ot_torrent*)(torrents_list->data))[j] ).peer_list; |
794 | for( k=0; k<OT_POOLS_COUNT; ++k ) { | 786 | for( k=0; k<OT_POOLS_COUNT; ++k ) { |
@@ -828,9 +820,10 @@ size_t return_stats_for_slash24s_old( char *reply, size_t amount, ot_dword thres | |||
828 | 820 | ||
829 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { | 821 | size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int is_tcp ) { |
830 | int exactmatch; | 822 | int exactmatch; |
831 | size_t peer_count, seed_count, index; | 823 | size_t index; |
832 | ot_vector *torrents_list = &all_torrents[*hash[0]]; | 824 | ot_vector *torrents_list = hash_to_bucket( all_torrents, hash ); |
833 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); | 825 | ot_torrent *torrent = binary_search( hash, torrents_list->data, torrents_list->size, sizeof( ot_torrent ), OT_HASH_COMPARE_SIZE, &exactmatch ); |
826 | ot_peerlist *peer_list; | ||
834 | 827 | ||
835 | if( !exactmatch ) { | 828 | if( !exactmatch ) { |
836 | if( is_tcp ) | 829 | if( is_tcp ) |
@@ -842,33 +835,27 @@ size_t remove_peer_from_torrent( ot_hash *hash, ot_peer *peer, char *reply, int | |||
842 | return (size_t)20; | 835 | return (size_t)20; |
843 | } | 836 | } |
844 | 837 | ||
845 | for( peer_count = seed_count = index = 0; index<OT_POOLS_COUNT; ++index ) { | 838 | peer_list = torrent->peer_list; |
846 | peer_count += torrent->peer_list->peers[index].size; | 839 | for( index = 0; index<OT_POOLS_COUNT; ++index ) { |
847 | seed_count += torrent->peer_list->seed_count[index]; | 840 | switch( vector_remove_peer( &peer_list->peers[index], peer, index == 0 ) ) { |
848 | |||
849 | switch( vector_remove_peer( &torrent->peer_list->peers[index], peer, index == 0 ) ) { | ||
850 | case 0: continue; | 841 | case 0: continue; |
851 | case 2: torrent->peer_list->seed_count[index]--; | 842 | case 2: peer_list->seed_counts[index]--; |
852 | seed_count--; | 843 | peer_list->seed_count--; |
853 | case 1: default: | 844 | case 1: default: |
854 | peer_count--; | 845 | peer_list->peer_count--; |
855 | goto exit_loop; | 846 | goto exit_loop; |
856 | } | 847 | } |
857 | } | 848 | } |
858 | 849 | ||
859 | exit_loop: | 850 | exit_loop: |
860 | for( ++index; index < OT_POOLS_COUNT; ++index ) { | ||
861 | peer_count += torrent->peer_list->peers[index].size; | ||
862 | seed_count += torrent->peer_list->seed_count[index]; | ||
863 | } | ||
864 | 851 | ||
865 | if( is_tcp ) | 852 | if( is_tcp ) |
866 | return sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", seed_count, peer_count - seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 853 | return sprintf( reply, "d8:completei%zde10:incompletei%zde8:intervali%ie5:peers0:e", peer_list->seed_count, peer_list->peer_count - peer_list->seed_count, OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
867 | 854 | ||
868 | /* else { Handle UDP reply */ | 855 | /* else { Handle UDP reply */ |
869 | ((ot_dword*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); | 856 | ((ot_dword*)reply)[2] = htonl( OT_CLIENT_REQUEST_INTERVAL_RANDOM ); |
870 | ((ot_dword*)reply)[3] = peer_count - seed_count; | 857 | ((ot_dword*)reply)[3] = peer_list->peer_count - peer_list->seed_count; |
871 | ((ot_dword*)reply)[4] = seed_count; | 858 | ((ot_dword*)reply)[4] = peer_list->seed_count; |
872 | return (size_t)20; | 859 | return (size_t)20; |
873 | } | 860 | } |
874 | 861 | ||
@@ -893,7 +880,7 @@ void deinit_logic( void ) { | |||
893 | size_t j; | 880 | size_t j; |
894 | 881 | ||
895 | /* Free all torrents... */ | 882 | /* Free all torrents... */ |
896 | for(i=0; i<256; ++i ) { | 883 | for(i=0; i<OT_BUCKET_COUNT; ++i ) { |
897 | if( all_torrents[i].size ) { | 884 | if( all_torrents[i].size ) { |
898 | ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data; | 885 | ot_torrent *torrents_list = (ot_torrent*)all_torrents[i].data; |
899 | for( j=0; j<all_torrents[i].size; ++j ) | 886 | for( j=0; j<all_torrents[i].size; ++j ) |
@@ -902,6 +889,7 @@ void deinit_logic( void ) { | |||
902 | } | 889 | } |
903 | } | 890 | } |
904 | byte_zero( all_torrents, sizeof (all_torrents)); | 891 | byte_zero( all_torrents, sizeof (all_torrents)); |
892 | byte_zero( all_torrents_clean, sizeof (all_torrents_clean)); | ||
905 | byte_zero( &changeset, sizeof( changeset ) ); | 893 | byte_zero( &changeset, sizeof( changeset ) ); |
906 | changeset_size = 0; | 894 | changeset_size = 0; |
907 | } | 895 | } |